Merge branch 'master' into release/20190925

# Conflicts:
#	android/sdk/src/main/java/org/apache/weex/bridge/WXParams.java
diff --git a/.gitignore b/.gitignore
index 4a9783d..1c5e235 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,6 +50,7 @@
 android/HeronAndroid/.externalNativeBuild/
 
 # release
+apache-weex-incubating-*
 apache_release_temp
 RELEASE_NOTE.md
 RELEASE_AUDIT.LOG
diff --git a/.rat-excludes b/.rat-excludes
index 45a4dce..6a131ce 100644
--- a/.rat-excludes
+++ b/.rat-excludes
@@ -1,11 +1,18 @@
-\.gitignore
-\.git/.*
-ios/playground 
-.rat-excludes
-build
-.*\.json
-Info\.plist
-.*\.xml
-.*\.pch
-main\.js
-\./ios/playground/Pods/.*
+index.js
+array.js
+dep.js
+object.js
+observer.js
+state.js
+watcher.js
+WXDataStructureUtil.java
+json11.cc
+json11.hpp
+modp_b64_data.h
+modp_b64.cc
+modp_b64.h
+icu_utf.h
+icu_utf.cpp
+jni_generator.py
+futex.h
+base64.hpp
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index d9f4191..6ecd0eb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,6 +7,8 @@
       - env: TEST_SUITE=danger 
       - env: TEST_SUITE=jsfm
       - env: TEST_SUITE=ios
+        os: osx
+        osx_image: xcode11.2
         language: objective-c
       - env: TEST_SUITE=android ABI=armeabi-v7a
         language: android
@@ -34,7 +36,8 @@
             - extra-android-m2repository 
       # static check
       - env: TEST_SUITE=static_code_analysis OCLINT=true
-        osx_image: xcode7.2
+        os: osx
+        osx_image: xcode11.2
         language: objective-c
       - env: TEST_SUITE=static_code_analysis ANDROID_LINT=true
         language: android
@@ -112,7 +115,7 @@
         git submodule update --init --remote
         cd weex-playground/ios && bash update_podfile_for_travisci.sh
         cd ../../ && npm install
-        cd weex-playground/ios && pod install --repo-update
+        cd weex-playground/ios && bundle install && pod install --repo-update
         cd ../../
     fi
     
@@ -137,8 +140,10 @@
         esac
         if npm run danger -- ci --dangerfile ./dangerfile-android.js | grep -q "hasAndroidFile" ; then
           cd android
-          ./gradlew clean assembleRelease -PbuildRuntimeApi=true ${GRADLE_ABI} --info || exit 1
-          ./gradlew assembleRelease -PbuildRuntimeApi=false ${GRADLE_ABI} --info || exit 1
+          ./gradlew clean assembleRelease --quiet -PbuildRuntimeApi=true ${GRADLE_ABI} -PapachePackageName="false" || exit 1
+          ./gradlew assembleRelease --quiet ${GRADLE_ABI} -PbuildRuntimeApi=false -Pjsc_url="https://raw.githubusercontent.com/apache/incubator-weex/release/0.26/android/sdk/weex_sdk-0.26.0.aar" -Paar_name="weex_sdk" -PJSInterpolatorName="JavaScriptCore" -PapachePackageName="false" || exit 1
+          ./gradlew :weex_sdk:assembleRelease --quiet -PbuildRuntimeApi=true ${GRADLE_ABI} -PapachePackageName="true" || exit 1
+          ./gradlew :weex_sdk:assembleRelease --quiet  ${GRADLE_ABI} -PbuildRuntimeApi=false -Pjsc_url="https://raw.githubusercontent.com/apache/incubator-weex/release/0.26/android/sdk/weex_sdk-0.26.0.aar" -Paar_name="weex_sdk" -PJSInterpolatorName="JavaScriptCore" -PapachePackageName="true" || exit 1
         fi
         ;;
       "jsfm" )
@@ -188,7 +193,8 @@
       if npm run danger -- ci --dangerfile ./dangerfile-static-check.js | grep -q "hasAndroidFile" ; then
         echo "hasAndroidFile"
         cd android
-        ./gradlew :weex_sdk:lint --quiet
+        ./gradlew :weex_sdk:lintLegacyRelease -PapachePackageName="false" --quiet
+        ./gradlew :weex_sdk:lintApacheRelease -PapachePackageName="true" --quiet
         export TITLE="AndroidLint Result"
         cd ../ && npm run danger -- ci -i androidlint --dangerfile ./dangerfile-output.js || exit 1
       fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5775a3e..e84c768 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@
 * Unified C++ log system of WeexCore.
 
 ### Android
-*  Upgrade targetsdk & compilesdk to 28
+* Upgrade targetsdk & compilesdk to 28
+* Change Android package name from `com.taobao.weex` to `org.apache.weex`, ref [link](https://github.com/apache/incubator-weex/tree/master/android#build-types)
+* Switch to BSD-Licensed [android-jsc](https://www.npmjs.com/package/jsc-android) as the default JavaScript Interpreter.
 
 ## Main Bugfix
diff --git a/HOW-TO-BUILD.md b/HOW-TO-BUILD.md
index a07099f..ee73899 100644
--- a/HOW-TO-BUILD.md
+++ b/HOW-TO-BUILD.md
@@ -1,5 +1,5 @@
 # Weex Apache Source Release
-Weex produce SDKs to integrate with iOS/Android/Mobile web applications. This file will cover how to build Weex from source. You can either use the script we provided or manually build from source step by step.
+Weex produce SDKs to integrate with iOS/Android/Mobile web applications. This file will cover how to build Weex from command line. You can either use the script we provided or manually build from source step by step.
 See `README.md` for further information about the Weex Framework.
 
 Weex SDK includes 3 different SDKs to use in corresponding system/browser:
@@ -9,32 +9,36 @@
 
 See our [guide in our website](http://weex.apache.org/guide/integrate-to-your-app.html) to learn more about how to integrate Weex SDK into your app.
 
-## Build Environment
-The environment required to build weex is:
-* Android SDK:
-    * NodeJS 4.0+
-    * JDK 1.6+
-    * Android SDK(`$ANDROID_HOME` must be set properly)
-    * Gradle 2.0+
-    * NDK r18 and ndk 13 (**Both of them are needed**)
-    * [Ninja 1.8.2+](https://ninja-build.org/)
-    * CMake 3.9.0+
-* iOS SDK:
-    * NodeJS 4.0+
-    * XCode & Command Tools 8.0+
-* Mobile web SDK:
-    * NodeJS 4.0+
+# Build Environment
+The environment required to build weex is categorized by platforms.
+
+## Android
+* JDK `1.8+`
+* Android SDK Platform 28
+  * `ANDROID_HOME` must be configured by using `export ANDROID_HOME=/path_to_sdk`
+  * Normally, you should install [Android Studio](https://developer.android.com/studio) to get Android SDK Platform 28 installed.
+* Gradle 4.10+
+* NDK `r18`
+  * `ANDROID_NDK_HOME` must be configured by using `export ANDROID_NDK_HOME=/path_to_ndk`
+  * Higher version of NDK than `r18` isn't not tested yet.
+* CMake 3.4.1+
+
+## iOS
+* Install [iOS Environment](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppStoreDistributionTutorial/Setup/Setup.html)
+* Install [CocoaPods](https://guides.cocoapods.org/using/getting-started.html)
+* XCode Command Tools 8.0+
+
+## Mobile
+* NodeJS 4.0+
 
 This article was tested in MacOSX system.
 
 # Build All by Script
 
 This script will build Android and iOS SDKs:
-> `$ bash scripts/build_from_source.sh $NDK13_dir $NDK_16dir`
+> `$ bash scripts/build_from_source.sh `
 
-The `$NDK18_dir` should be the directory of NDK 18, otherwise the Android build would failed.
-
-This may take a while. After that, you can look in `dist/`, `android/sdk/build/output/` and `ios/sdk/Products` for Web/Android/iOS SDK artifacts.
+This may take a while. After that, you can look in `dist/`, `android/sdk/build/outputs/aar` and `ios/sdk/Products` for Web / Android / iOS SDK artifacts.
 
 # Build for Platforms
 
@@ -53,37 +57,25 @@
 
 ### Before build Native SDK
 Move `min` version to Native SDK folder, which will be used by native SDK build.
-> `cp packages/weex-js-framework/index.min.js ios_sdk/WeexSDK/Resources/main.js`
-> `cp packages/weex-js-framework/index.min.js android_sdk/assets/main.js`
+
+```
+cp packages/weex-js-framework/index.min.js ios/sdk/WeexSDK/Resources/main.js
+cp packages/weex-js-framework/index.min.js android/sdk/assets/main.js
+```
 
 ## Build Android SDK
+1. Install the [Android environment](#android).
+2. Execute the following command
 
-check env
+    ```
+    cd android
+    ./gradlew :weex_sdk:clean :weex_sdk:assembleRelease
+    ```
 
-- you have gradle installed, see more details about 'how to install gradle' on the [gradle website](https://gradle.org/install).
-- [NDK r18](https://developer.android.com/ndk/downloads/older_releases.html)
-- edit local.propteries (in `Android` dir)
-
-	```
-	ndk.dir=/Users/{user}/Library/Android/sdk/ndk-bundle-r18
-	sdk.dir=/Users/{user}/Library/Android/sdk
-	```
-
-then do buid
-
-> cd Android/sdk
-
-> ../gradlew clean assemble
-
-
-artifacts path:
-
-` android/sdk/build/outputs/aar`
-
-You can now import the aar file to your android project.
+3. Output can be found at `android/sdk/build/outputs/aar`
 
 ## Build iOS SDK
 Execute command below to compile iOS SDK:
-> `$ xcodebuild -project ios_sdk/WeexSDK.xcodeproj -target WeexSDK_MTL`
+> `$ xcodebuild -project ios/sdk/WeexSDK.xcodeproj -target WeexSDK_MTL`
 
 Then you'll find the iOS library(Framework file) under `ios_sdk/Products`.
diff --git a/LICENSE b/LICENSE
index 8cf0003..4d5db27 100644
--- a/LICENSE
+++ b/LICENSE
@@ -187,7 +187,7 @@
       same "printed page" as the copyright notice for easier
       identification within third-party archives.
 
-   Copyright [yyyy] [name of copyright owner]
+   Copyright 2019 Apache Weex (Incubating)
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -244,10 +244,9 @@
 
 
 This product bundles Guava v20.0, which is available under a "Apache" license. For details, see https://github.com/google/guava/blob/v20.0/COPYING and following files:
-  android_sdk/src/main/java/org/apache/taobao/weex/utils/WXDataStructureUtil.java
+  android/sdk/src/main/java/org/apache/weex/utils/WXDataStructureUtil.java
 
 This product bundles json11 v1.0.0, which is available under a "MIT" license. For details, see https://github.com/dropbox/json11/tree/v1.0.0 and following files:
-   weex_core/Source/third_party/json11/CMakeLists.txt
    weex_core/Source/third_party/json11/json11.cc
    weex_core/Source/third_party/json11/json11.hpp
 
@@ -408,305 +407,6 @@
 This product bundles Android Open Source Project vandroid-4.2.2_r1, which is available under a "BSD" license. For details, see https://android.googlesource.com/platform/bionic/+/android-4.2.2_r1/libc/README and following files:
   weex_core/Source/IPC/futex.h
 
-This product bundles Webkit 2.17.4, which is available under a "BSD-style" license. For details, reference https://webkit.org/licensing-webkit/ for license and see https://svn.webkit.org/repository/webkit/releases/WebKitGTK/webkit-2.17.4 for following files:
-
-   Bmalloc in WebKit:
-      weex_core/Source/android/jsengine/dependence/bmalloc:
-         CMakeLists.txt
-         ChangeLog
-         Makefile
-
-      weex_core/Source/android/jsengine/dependence/bmalloc/Configurations:
-         Base.xcconfig
-         DebugRelease.xcconfig
-         bmalloc.xcconfig
-         mbmalloc.xcconfig
-
-      weex_core/Source/android/jsengine/dependence/bmalloc/bmalloc:
-         Algorithm.h
-         Allocator.cpp
-         Allocator.h
-         AsyncTask.h
-         AvailableMemory.cpp
-         AvailableMemory.h
-         BAssert.h
-         BPlatform.h
-         BumpAllocator.h
-         BumpRange.h
-         Cache.cpp
-         Cache.h
-         Chunk.h
-         Deallocator.cpp
-         Deallocator.h
-         DebugHeap.cpp
-         DebugHeap.h
-         Environment.cpp
-         Environment.h
-         FixedVector.h
-         Heap.cpp
-         Heap.h
-         Inline.h
-         LargeMap.cpp
-         LargeMap.h
-         LargeRange.h
-         LineMetadata.h
-         List.h
-         Logging.cpp
-         Logging.h
-         Map.h
-         Mutex.h
-         Object.h
-         ObjectType.cpp
-         ObjectType.h
-         PerProcess.h
-         PerThread.h
-         Range.h
-         ScopeExit.h
-         Sizes.h
-         SmallLine.h
-         SmallPage.h
-         StaticMutex.cpp
-         StaticMutex.h
-         Syscall.h
-         VMAllocate.h
-         VMHeap.cpp
-         VMHeap.h
-         Vector.h
-         Zone.cpp
-         Zone.h
-         bmalloc.h
-         mbmalloc.cpp
-
-      weex_core/Source/android/jsengine/dependence/bmalloc/bmalloc/darwin:
-         BSoftLinking.h
-
-      weex_core/Source/android/jsengine/dependence/bmalloc/bmalloc.xcodeproj:
-         project.pbxproj
-
-   ICU in WebKit:
-      weex_core/Source/android/jsengine/dependence/icu:
-         LICENSE
-         README
-
-      weex_core/Source/android/jsengine/dependence/icu/unicode:
-         localpointer.h
-         parseerr.h
-         platform.h
-         ptypes.h
-         putil.h
-         ucal.h
-         uchar.h
-         ucnv.h
-         ucnv_err.h
-         ucol.h
-         uconfig.h
-         ucurr.h
-         udat.h
-         udatpg.h
-         udisplaycontext.h
-         uenum.h
-         uformattable.h
-         uiter.h
-         uloc.h
-         umachine.h
-         umisc.h
-         unorm.h
-         unorm2.h
-         unum.h
-         unumsys.h
-         urename.h
-         uscript.h
-         uset.h
-         ustring.h
-         utf.h
-         utf16.h
-         utf8.h
-         utf_old.h
-         utypes.h
-         uvernum.h
-         uversion.h
-   
-   JavaScriptCore in WebKit:
-      weex_core/Source/include/JavaScriptCore/API:
-         APICallbackFunction.h
-         APICast.h
-         APIUtils.h
-         JSAPIWrapperObject.h
-         JSBase.h
-         JSBasePrivate.h
-         JSCTestRunnerUtils.h
-         JSCallbackConstructor.h
-         JSCallbackFunction.h
-         JSCallbackObject.h
-         JSCallbackObjectFunctions.h
-         JSClassRef.h
-         JSContext.h
-         JSContextInternal.h
-         JSContextPrivate.h
-         JSContextRef.h
-         JSContextRefInspectorSupport.h
-         JSContextRefInternal.h
-         JSContextRefPrivate.h
-         JSExport.h
-         JSManagedValue.h
-         JSManagedValueInternal.h
-         JSObjectRef.h
-         JSObjectRefPrivate.h
-         JSRemoteInspector.h
-         JSRetainPtr.h
-         JSScriptRefPrivate.h
-         JSStringRef.h
-         JSStringRefBSTR.h
-         JSStringRefCF.h
-         JSStringRefPrivate.h
-         JSTypedArray.h
-         JSValue.h
-         JSValueInternal.h
-         JSValueRef.h
-         JSVirtualMachine.h
-         JSVirtualMachineInternal.h
-         JSWeakObjectMapRefInternal.h
-         JSWeakObjectMapRefPrivate.h
-         JSWrapperMap.h
-         JavaScript.h
-         JavaScriptCore.h
-         ObjCCallbackFunction.h
-         ObjcRuntimeExtras.h
-         OpaqueJSString.h
-         WebKitAvailability.h
-
-      weex_core/Source/include/JavaScriptCore/ForwardingHeaders/JavaScriptCore:
-         APICast.h
-         JSBase.h
-         JSCTestRunnerUtils.h
-         JSContextRef.h
-         JSObjectRef.h
-         JSObjectRefPrivate.h
-         JSRetainPtr.h
-         JSStringRef.h
-         JSStringRefCF.h
-         JSTypedArray.h
-         JSValueRef.h
-         JavaScript.h
-         JavaScriptCore.h
-         OpaqueJSString.h
-         WebKitAvailability.h
-
-   Other files in Webkit:
-      weex_core/Source/android/jsengine/dependence:
-         OptionsCommon.cmake
-         OptionsJSCOnly.cmake
-
-   The copyright for files above is listed below:
-      weex_core/Source/android/jsengine/dependence/icu:
-         COPYRIGHT AND PERMISSION NOTICE
-
-         Copyright (c) 1995-2006 International Business Machines Corporation and others
-
-         All rights reserved.
-
-         Permission is hereby granted, free of charge, to any person obtaining a copy of this
-         software and associated documentation files (the "Software"), to deal in the Software
-         without restriction, including without limitation the rights to use, copy, modify,
-         merge, publish, distribute, and/or sell copies of the Software, and to permit persons
-         to whom the Software is furnished to do so, provided that the above copyright notice(s)
-         and this permission notice appear in all copies of the Software and that both the above
-         copyright notice(s) and this permission notice appear in supporting documentation.
-
-         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-         INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-         PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER
-         OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR
-         CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-         PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-         OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-         Except as contained in this notice, the name of a copyright holder shall not be used in
-         advertising or otherwise to promote the sale, use or other dealings in this Software
-         without prior written authorization of the copyright holder.
-      
-      weex_core/Source/include/JavaScriptCore:
-
-         /*
-         * Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
-         * Copyright (C) 2006 Apple Inc.  All rights reserved.
-         * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
-         * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
-         * Copyright (C) 2006, 2008, 2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2007 Apple Inc.  All rights reserved.
-         * Copyright (C) 2008 Apple Inc.  All rights reserved.
-         * Copyright (C) 2008, 2009, 2010, 2014 Apple Inc. All Rights Reserved.
-         * Copyright (C) 2009 Apple Inc.  All rights reserved.
-         * Copyright (C) 2010 Apple Inc. All rights reserved.
-         * Copyright (C) 2012 Apple Inc. All rights reserved.
-         * Copyright (C) 2013 Apple Inc. All rights reserved.
-         * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2013, 2017 Apple Inc. All rights reserved.
-         * Copyright (C) 2014 Apple Inc. All rights reserved.
-         * Copyright (C) 2015 Apple Inc.  All rights reserved.
-         * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-         * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-         * Copyright (C) 2008 Alp Toker <alp@atoker.com>
-         * Copyright (C) 2008 Kelvin W Sherlock (ksherlock@gmail.com)
-         * Copyright (C) 2015 Dominic Szablewski (dominic@phoboslab.org)
-         *
-         * Redistribution and use in source and binary forms, with or without
-         * modification, are permitted provided that the following conditions
-         * are met:
-         * 1. Redistributions of source code must retain the above copyright
-         *    notice, this list of conditions and the following disclaimer.
-         * 2. Redistributions in binary form must reproduce the above copyright
-         *    notice, this list of conditions and the following disclaimer in the
-         *    documentation and/or other materials provided with the distribution.
-         *
-         * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
-         * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-         * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
-         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-         * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-         * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-         * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
-         */
-
-         weex_core/Source/android/jsengine/dependence/bmalloc:
-
-         /*
-         * Copyright (C) 2007, 2008, 2011-2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
-         * Copyright (C) 2014 Apple Inc. All rights reserved.
-         * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
-         * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
-         * Copyright (C) 2016 Apple Inc. All rights reserved.
-         *
-         * Redistribution and use in source and binary forms, with or without
-         * modification, are permitted provided that the following conditions
-         * are met:
-         * 1.  Redistributions of source code must retain the above copyright
-         *     notice, this list of conditions and the following disclaimer.
-         * 2.  Redistributions in binary form must reproduce the above copyright
-         *     notice, this list of conditions and the following disclaimer in the
-         *     documentation and/or other materials provided with the distribution.
-         *
-         * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
-         * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-         * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-         * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-         * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-         * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-         */
-
 This product bundles files from Boost under "Boost Software License". For more details, reference http://www.boost.org/LICENSE_1_0.txt
   weex_core/Source/js_runtime/utils/base64.hpp
 
diff --git a/NOTICE b/NOTICE
index 81c698c..ea6b3ac 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,4 +1,4 @@
-Apache Weex
+Apache Weex (Incubating)
 Copyright 2019 The Apache Software Foundation
 
 This product includes software developed at
diff --git a/POSSIBLE-NOTICES-FOR-BIN-DIST b/POSSIBLE-NOTICES-FOR-BIN-DIST
deleted file mode 100644
index a0e2329..0000000
--- a/POSSIBLE-NOTICES-FOR-BIN-DIST
+++ /dev/null
@@ -1,98 +0,0 @@
-Apache Weex
-Copyright 2018 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
-This product contains software semver(http://semver.org/) developed
-by Tom Preston-Werner , licensed under the Creative Commons - CC BY 3.0 License.
-
-This product contains software core-js(https://github.com/zloirock/core-js) developed
-by Denis Pushkarev , licensed under the MIT License.
-
-This product contains software weex-rax-framework(https://github.com/alibaba/rax) developed
-by yuanyan  , licensed under the BSD-3-Clause License.
-
-This product contains software weex-vue-framework(https://github.com/vuejs/vue) developed
-by fkysly  , licensed under the MIT License.
-
-This product contains software weex-vue-render(https://github.com/weexteam/weex-vue-render) developed
-by MrRaindrop  , licensed under the Apache 2.0 License.
-
-This product contains software weex-styler(https://github.com/weexteam/weex-styler) developed
-by songsiqi  , licensed under the MIT License.
-
-This product contains software vuejs(https://github.com/vuejs/vue) developed
-by Yuxi Evan You , licensed under the MIT License.
-
-This product contains software fastjson(https://github.com/alibaba/fastjson) developed
-by alibaba inc.  , licensed under the Apache 2.0 License.
-
-This product contains software dexposed(https://github.com/alibaba/dexposed) developed
-by alibaba inc.  , licensed under the Apache 2.0 License.
-
-This product contains software js_engine(https://github.com/alibaba/weex_js_engine/) developed
-by alibaba inc.  , licensed under the Apache 2.0 License.
-
-This product contains software bindingX(https://github.com/alibaba/bindingx) developed
-by alibaba inc.  , licensed under the Apache 2.0 License.
-
-This product contains software loopj(https://github.com/loopj/android-async-http) developed
-by loopj , licensed under the Apache 2.0 License.
-
-This product contains software fresco(https://github.com/facebook/fresco) developed
-by facebook , licensed under the BSD-3-Clause License.
-
-This product contains software animated-gif(https://github.com/facebook/fresco) developed
-by facebook , licensed under the BSD-3-Clause License.
-
-This product contains software SocketRocket(https://github.com/facebook/SocketRocket) developed
-by facebook , licensed under the BSD-3-Clause License.
-
-This product contains software zxing(https://github.com/zxing/zxing) developed
-by zxing , licensed under the Apache 2.0 License.
-
-This product contains software okhttp(https://github.com/square/okhttp) developed
-by square , licensed under the Apache 2.0 License.
-
-This product contains software okio(https://github.com/square/okio) developed
-by square , licensed under the Apache 2.0 License.
-
-This product contains software scalpel(https://github.com/JakeWharton/scalpel) developed
-by Jake Wharton , licensed under the Apache 2.0 License.
-
-This product contains software espresso-idling-resource(https://google.github.io/android-testing-support-library/docs/espresso/idling-resource/) developed
-by google , licensed under the Apache 2.0 License.
-
-This product contains software AOSP(https://source.android.com/) developed
-by The Android Open Source Project , licensed under the Apache 2.0 License.
-
-This product contains software SDWebImage(https://github.com/rs/SDWebImage) developed
-by Olivier Poitrey  , licensed under the MIT License.
-
-This product contains software Guava(https://github.com/google/guava) developed
-by google  , licensed under the Apache License.
-
-This product contains shelljs Guava(https://github.com/shelljs/shelljs) developed
-by shelljs  , licensed under BSD 3-clause "New" or "Revised" License.
-
-This product contains software fpconv(https://github.com/night-shift/fpconv) developed
-by night-shift  , licensed under the MIT License.
-
-This product contains software rapidjson(https://github.com/Tencent/rapidjson) developed
-by tencent  , licensed under the MIT License.
-
-This product contains software flexbox-layout(https://github.com/google/flexbox-layout) developed
-by google  , licensed under the Apache License.
-
-This product contains software IPC(https://source.android.com/) developed
-by google  , licensed under the Apache License.
-
-This product contains software JNI(https://chromium.googlesource.com/) developed
-by google, licensed under the BSD-style License.
-
-This product contains software modp(http://modp.com/release/base64) developed
-by modp, licensed under the BSD-style License.
-
-This product contains software jni_generator(https://chromium.googlesource.com/) developed
-by google, licensed under the BSD-style License.
diff --git a/README.md b/README.md
index 5ff48fe..7770d94 100644
--- a/README.md
+++ b/README.md
@@ -4,24 +4,35 @@
 
 [![Build Status](https://travis-ci.org/apache/incubator-weex.svg?branch=master)](https://travis-ci.org/apache/incubator-weex/)
 
+## Join Us
+**Join us through [mailing list](https://weex.apache.org/guide/contribute/how-to-contribute.html#mailing-list).**
+
+## Convenience Distribution 
+**Since 0.28.0, Weex would publish two convince binary in each release for Android, please [read the documentation about the detail](major_change.html).**
+
+**Please take the above link seriously, otherwise you would be able to use the latest version of Weex.**
+
 | platform | status |
 | -------- | ------ |
-| Android | [![Download](https://api.bintray.com/packages/alibabaweex/maven/weex_sdk/images/download.svg)](https://bintray.com/alibabaweex/maven/weex_sdk/_latestVersion) |
+| Android | [sdk ![Download](https://api.bintray.com/packages/weex/Android/sdk/images/download.svg)](https://bintray.com/weex/Android/sdk/_latestVersion) Or [sdk_legacy ![Download](https://api.bintray.com/packages/weex/Android/sdk_legacy/images/download.svg)](https://bintray.com/weex/Android/sdk_legacy/_latestVersion) |
 | iOS | [![Pod version](https://badge.fury.io/co/WeexSDK.svg)](https://cocoapods.org/pods/WeexSDK) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) |
-| [Mobile Web](https://github.com/weexteam/weex-vue-render) | [![npm version](https://badge.fury.io/js/weex-html5.svg)](https://www.npmjs.com/package/weex-vue-render) |
+| [Mobile Web](https://github.com/weexteam/vue-render-for-apache-weex) | [![npm version](https://badge.fury.io/js/weex-vue-render.svg)](https://www.npmjs.com/package/weex-vue-render) |
 
 Support Android 4.1 (API 16), iOS 8.0+ and WebKit 534.30+.
 
-**Note: Please note the above download distribution is only for users' users' convenience. Weex Release is always in the format of [source code](https://weex.apache.org/download/download.html).**
+**FYI: The [mobile web render](https://github.com/weexteam/vue-render-for-apache-weex) is not supported by Apache Weex officially**
 
 ## For Windows
+First of all, compiling or building Weex from Windows is not support officially.
 
-Please ***INSTALL [Git for Windows](https://git-scm.com/download/win)*** and run all the following commands in git-bash.
+You could install [Git for Windows](https://git-scm.com/download/win) and run all the following commands in git-bash.
+
+Good Luck.
 
 ## Meet Weex
 
-* Install [Weex Playground App](https://weex.apache.org/tools/playground.html) to see examples we already written.
-* If you want to write a demo, install [weex-toolkit](https://www.npmjs.com/package/weex-toolkit) in [Node.js](http://nodejs.org/) 8.0+ and
+* Install [Weex Playground](https://weex.apache.org/tools/playground.html) to see examples we already written.
+* If you want to write a demo, install [weex-cli](https://www.npmjs.com/package/weex-toolkit) in [Node.js](http://nodejs.org/) 8.0+ and
 * Run `weex init` to generate & start a simple project in an empty folder.
 * Follow the instructions in the project README.
 * Enjoy it.
@@ -32,41 +43,29 @@
 * [Documents](http://weex.apache.org/references)
 
 ### Android
+**You should install [android environment](./HOW-TO-BUILD.md#android) before building.**
 
-* Prerequisites
-  * Install [Node.js](http://nodejs.org/) 8.0+
-  * Under project root
-    * `npm install`, install project
-    * `./start`
-    * Install [Android Environment](http://developer.android.com/training/basics/firstapp/index.html)
-    * Install [NDK](https://developer.android.com/ndk/) r18
-    * Install [Cmake](https://cmake.org/download/) 3.9.0+
-* Run playground, In Android Studio
-    * Open `android/playground`
-    * In `app/java/com.alibaba.weex/IndexActivity`, modify `CURRENT_IP` to your local IP
-    * Click <img src="http://gtms04.alicdn.com/tps/i4/TB1wCcqMpXXXXakXpXX3G7tGXXX-34-44.png" height="16" > (`Run` button)
-* [Add an example](./examples/README.md#add-an-example)
+You can either build Weex from IDE (*Android Studio*) or command line.
 
-#### Runtime
+#### Build From Android Studio
+1. Open `android` directory in Android Studio.
+2. Run `git submodule update --init --remote` in `android` directory if this is the first time you try to run Weex.
 
-On Android Platform , Weex code is executed in [weex_js_engine](https://github.com/alibaba/weex_js_engine/tree/bridge_branch_mergeTimer) which is based on JavaScriptCore engine.
+#### Build From Command Line
+Please read [How To Build](./HOW-TO-BUILD.md) for detail.
 
 ### iOS
-* run playground
-  * Prerequisites
-    * Install [Node.js](http://nodejs.org/) 8.0+
-      * Under project root
-          * `npm install`, install project
-          * `./start`
-      * Install [iOS Environment](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppStoreDistributionTutorial/Setup/Setup.html)
-      * Install [CocoaPods](https://guides.cocoapods.org/using/getting-started.html)
-  * Run playground
-      * `cd ios/playground`
-      * `pod install`
-      * Open `WeexDemo.xcworkspace` in Xcode
-      * Click <img src="http://img1.tbcdn.cn/L1/461/1/5470b677a2f2eaaecf412cc55eeae062dbc275f9" height="16" > (`Run` button) or use default shortcut `cmd + r` in Xcode
-      * If you want to run the demo on your device, don't need to modify `CURRENT_IP` manually. ~~In `DemoDefine.h`(you can search this file by Xcode default shortcut `cmd + shift + o`), modify `CURRENT_IP` to your local IP~~
-  * [Add an example](./examples/README.md#add-an-example)
+**You should install [iOS environment](./HOW-TO-BUILD.md#ios) before building.**
+
+You can either build Weex from IDE (*XCode*) or command line.
+
+#### Build From XCode
+* Run playground
+  * `cd ios/playground`
+  * `pod install`
+  * Open `WeexDemo.xcworkspace` in Xcode
+  * Click <img src="http://img1.tbcdn.cn/L1/461/1/5470b677a2f2eaaecf412cc55eeae062dbc275f9" height="16" > (`Run` button) or use default shortcut `cmd + r` in Xcode
+  * If you want to run the demo on your device, don't need to modify `CURRENT_IP` manually. ~~In `DemoDefine.h`(you can search this file by Xcode default shortcut `cmd + shift + o`), modify `CURRENT_IP` to your local IP~~
 * integrate to your application
 
   - **[CocoaPods](https://cocoapods.org)**
@@ -85,19 +84,20 @@
    ```
    Run `carthage update`, and you should now have the latest version of   `WeexSDK` in your `Carthage` folder.
 
+#### Build From Command Line
+Please read [How To Build](./HOW-TO-BUILD.md) for detail.
+
 ### Mobile Web
+**Vue Render for Apache Weex is a third party plugin, and not developed nor maintained by Apache Weex.**
 
-see [weex-vue-render](https://github.com/weexteam/weex-vue-render).
+see [Vue Render for Apache Weex](https://github.com/weexteam/vue-render-for-apache-weex).
 
-## Scripts
+## Third part plugin
+There is a third party plugin provides for debugging purpose.
+* [Android](https://weex.apache.org/guide/debug/integrate-devtool-to-android.html)
+* [iOS](https://weex.apache.org/guide/debug/integrate-devtool-to-ios.html)
 
-See [SCRIPTS.md](./SCRIPTS.md) for more information.
-
-## IDE Plugin & Syntax Highlight & DevTool
-
-Weex team have developed a [DevTool](https://github.com/weexteam/weex-devtool) to help you to improve the debugging efficiency.
-
-See more stuff on [this wiki page](https://github.com/alibaba/weex/wiki/Weex-Community)
+You can also view this page for all [third party plugin](https://weex.apache.org/tools).
 
 ## Weex Community
 * [Mailing List](https://weex.apache.org/guide/contribute/how-to-contribute.html#mailing-list) Weex Mailing List, where most discussion happens.
diff --git a/WeexSDK.podspec b/WeexSDK.podspec
index af264dd..050e37f 100644
--- a/WeexSDK.podspec
+++ b/WeexSDK.podspec
@@ -4,7 +4,7 @@
 
   s.name         = "WeexSDK"
 
-  s.version      = "0.26.0"
+  s.version      = "0.28.0"
 
   s.summary      = "WeexSDK Source."
 
@@ -12,21 +12,12 @@
                    A framework for building Mobile cross-platform UI
                    DESC
 
-  s.homepage     = "https://github.com/alibaba/weex"
+  s.homepage     = "https://github.com/apache/incubator-weex"
   s.license = {
-    :type => 'Copyright',
-    :text => <<-LICENSE
-           Alibaba-INC copyright
-    LICENSE
+    :type => 'Apache-2.0'
   }
   s.authors      = {
-                    "cxfeng1"      => "cxfeng1@gmail.com",
-                    "boboning"     => "ningli928@163.com",
-                    "yangshengtao" => "yangshengtao1314@163.com",
-                    "kfeagle"      => "sunjjbobo@163.com",
-                    "acton393"     => "zhangxing610321@gmail.com",
-                    "wqyfavor"     => "wqyfavor88@gmail.com",
-                    "doumafang "   => "doumafang@gmail.com"
+                    "dev" => "dev@weex.apache.org"
                    }
   s.platform     = :ios
   s.ios.deployment_target = '9.0'
@@ -132,4 +123,4 @@
   
   s.libraries = 'c++'
 
-end
\ No newline at end of file
+end
diff --git a/android/README.md b/android/README.md
index 29507f8..c88cff2 100644
--- a/android/README.md
+++ b/android/README.md
@@ -2,8 +2,28 @@
 ## Install gradlew   
   See https://gradle.org/install#with-a-package-manager
 ## Build Weex   
-run `gradle build`   
-Playground app artifact will be under 'playground/build'
+run `./gradlew clean assembleRelease` to build `weex_sdk`
+
+### Build Types
+For historical reason, the java files of weex_sdk was under the package name of `com.taobao.weex`, despite the fact that they are under `org.apache.weex` now.
+
+In order to provide backward compatibility for users, there are two type of convince binary of Weex generated by different building argument.
+
+#### weex_sdk
+`weex_sdk` is the library we give officially support now, where all java files in `.aar` is under `org.apache.weex`.
+
+New users of Weex should always choose `weex_sdk`, while for existing users, using `weex_sdk` could cause compiling issues and you could use `weex_sdk_legacy` for temporary solution. See below for detail.
+
+#### weex_sdk_legacy
+`weex_sdk_legacy`  is provided only for backward compatibility reason, and **would not be maintained in the future**. Please migrate to `weex_sdk` when you are available.
+
+`weex_sdk_legacy` is built by `./gradlew clean assembleRelease -PapachePackageName="false"`, where all java files in `.aar` is under `com.taobao.weex`
+
+## Android-Studio integrated
+Double type `SHIFT` and enter `Build Variants`, will give you build variants window.
+* Select `apacheRelease` in the dropdown window of Active Build Variants to enable Android-Studio integrated for files under `org.apache.weex`
+* Select `legacyRelease` or `release` in the dropdown window of Active Build Variants to enable Android-Studio integrated for files under `com.taobao.weex`
+
 ## The submodule weex-playground
 [Weex Playground](https://github.com/apache/incubator-weex-playground) can be used to test and preview weex pages on Android and it has been added as a submodule.
 ### Relationship between weex and playground
@@ -12,12 +32,12 @@
 ### When to publish SNAPSHOT
 When some commits of  playground rely on unpublished features of weex-sdk,a SNAPSHOT of weex-sdk will be needed to support it.
 ### How to publish SNAPSHOT
- `cd android `  
-`./gradlew clean install ArtifactoryPublish -PweexVersion=$PUBLISH_VERSION -PbintrayUser=alibabaweex -PbintrayApiKey=$JCENTER_TOKEN `  
+
+```
+cd android
+./gradlew clean install ArtifactoryPublish -PgroupId="org.apache.weex" -PartifactName="sdk_legacy" -PapachePackageName="false" -PunbundlingJSC="true" -PbuildRuntimeApi=true -PweexVersion=$PUBLISH_VERSION -PbintrayUser=weex -PbintrayApiKey=$JCENTER_TOKEN 
+```
 
 * Explanation for variable:  
 $PUBLISH_VERSION The version of snapshot, like 0.26.1.3-SNAPSHOT  
-$JCENTER_TOKEN The private key for JCenter (https://bintray.com/alibabaweex/maven/weex_sdk/), which is the distribution channel for Android
-
-
-
+$JCENTER_TOKEN The private key for JCenter (https://bintray.com/alibabaweex/maven/weex_sdk/), which is the distribution channel for Android
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 3112b63..8898559 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,4 +1,21 @@
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
 buildscript {
     repositories {
         google()
@@ -36,8 +53,8 @@
     }
     buildscript {
         dependencies {
-            classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
-            classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
+            classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
+            classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
         }
         repositories {
             google()
@@ -58,6 +75,11 @@
     fastjsonLibVersion="1.1.70.android"
     //Default value for disableCov is false
     disableCov = project.hasProperty("disableCov") && disableCov.equals("true")
+    useApachePackageName = project.hasProperty('apachePackageName') ? project.property('apachePackageName').toBoolean() : false
+    unbundlingJSC = project.hasProperty('unbundlingJSC') ? project.property('unbundlingJSC').toBoolean() : false
+    artifactName = project.hasProperty('artifactName') ? project.property('artifactName') : 'weex_sdk'
+    groupId = project.hasProperty('groupId') ? project.property('groupId') : 'com.taobao.android'
+    weexVersion = project.hasProperty('weexVersion') ? project.getProperty('weexVersion') : '0.28.0.1'
     implementFromWeex = true
 }
 
diff --git a/android/gradle.properties b/android/gradle.properties
index 8583e59..c520341 100755
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -13,5 +13,4 @@
 #Mon Jun 27 20:06:22 CST 2016
 org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
 org.gradle.parallel=true
-android.enableAapt2=false
 android.enableD8=false
\ No newline at end of file
diff --git a/android/sdk/.gitignore b/android/sdk/.gitignore
index b173f6b..8074061 100755
--- a/android/sdk/.gitignore
+++ b/android/sdk/.gitignore
@@ -16,5 +16,8 @@
 assets/weex-rax-api.js
 .externalNativeBuild
 
-/libs/armeabi
+/libs/
+/src/main/jniLibs
 
+/src/legacyRelease/
+proguard-rules-legacy.pro
\ No newline at end of file
diff --git a/android/sdk/README.md b/android/sdk/README.md
deleted file mode 100755
index 239bde2..0000000
--- a/android/sdk/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-## Unit Test
-
-Unit test code is under 'src/test'. You can run unit test use command:   
-```bash
-./gradlew clean testDebugUnitTest jacocoTestReportDebug
-```
-This task will run all unit test and produce both unit test report and jacoco test coverage report in 'build/reports'.   
diff --git a/android/sdk/build.gradle b/android/sdk/build.gradle
index 2a9654e..15be1de 100755
--- a/android/sdk/build.gradle
+++ b/android/sdk/build.gradle
@@ -18,7 +18,7 @@
  */
  plugins {
      id "com.github.hierynomus.license" version "0.14.0"
-     id 'com.jfrog.artifactory' version '4.9.7'
+     id 'com.jfrog.artifactory' version '4.10.0'
  }
 
 apply plugin: 'com.android.library'
@@ -26,29 +26,15 @@
 apply plugin: 'com.jfrog.bintray'
 apply plugin: 'com.github.dcendents.android-maven'
 
-//if(!project.disableCov){
-//    apply plugin: 'com.vanniktech.android.junit.jacoco'
-//    junitJacoco {
-//        excludes = ['com/taobao/weex/dom/flex/**','com/taobao/weex/ui/view/refresh/circlebar/**']
-//    }
-//}
+apply from: 'buildSrc/jcenter.gradle'
+apply from: 'buildSrc/unstripped.gradle'
+apply from: 'buildSrc/checkStyle.gradle'
+apply from: 'buildSrc/download_jsc.gradle'
+apply from: 'buildSrc/packageName.gradle'
+apply from: 'buildSrc/asan.gradle'
 
-task checkstyle(type: Checkstyle) {
-    configFile file("${project.rootDir}/sdk/config/quality/checkstyle.xml") // Where my checkstyle config is...
-    // configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/config/quality/checkstyle/suppressions.xml").absolutePath // Where is my suppressions file for checkstyle is...
-    source 'src'
-    include '**/*.java'
-    exclude '**/gen/**'
-    exclude '**/test/**'
-    exclude '**/com/taobao/weex/dom/flex/**'
-    classpath = files()
-}
-
-checkstyle {
-    toolVersion = '6.9'
-}
-
-version = project.hasProperty('weexVersion') ? project.getProperty('weexVersion') : '0.26.0.1'
+version = project.weexVersion
+group = project.groupId
 
 //Check version, the version must have 4 sections. The leading three section must be number, and the last section is odd number with or without suffix string.
 if (!project.hasProperty('ignoreVersionCheck') || !project.getProperty('ignoreVersionCheck').equals("true")) {
@@ -117,11 +103,17 @@
 
     def android_project_dir = projectDir
 
-    def buildRuntimeApi = project.hasProperty('buildRuntimeApi') ? project.property('buildRuntimeApi') : false
+    def buildRuntimeApi = project.hasProperty('buildRuntimeApi') ? project.property('buildRuntimeApi').toBoolean() : true
+    def jsInterpolatorName = project.hasProperty('JSInterpolatorName') ? project.property('JSInterpolatorName') : 'jsc'
+    def initJSCPrivateApi = false
+    if (buildRuntimeApi){
+        initJSCPrivateApi = jsInterpolatorName =="JavaScriptCore"
+    }
 
     defaultConfig {
         buildConfigField "String", "buildJavascriptFrameworkVersion", "\"${jsfmVersion}\""
         buildConfigField "String", "buildVersion", "\"${version}\""
+        buildConfigField "String", "JSInterpolatorName", "\"${jsInterpolatorName}\""
         minSdkVersion project.minSdkVersion
         targetSdkVersion project.targetSdkVersion
 
@@ -149,8 +141,13 @@
                         '-DANDROID_STL=' + "${cxx_stl}",
                         '-DCMAKE_BUILD_TYPE=Release',
                         '-DANDROID_PROJECT_DIR=' + "${android_project_dir}",
-                        '-DENABLE_ASAN=false',
-                        '-DBUILD_RUNTIME_API='+"${buildRuntimeApi}"
+                        '-DENABLE_ASAN=false'
+                if(buildRuntimeApi){
+                    arguments '-DBUILD_RUNTIME_API='+"${buildRuntimeApi}"
+                    if (initJSCPrivateApi){
+                        arguments '-DINIT_JSC_PRIVATE_API='+"${initJSCPrivateApi}"
+                    }
+                }
                 if(project.hasProperty('enableASan') && "true" == project.getProperty('enableASan')) {
                     cppFlags "-fsanitize=address -fno-omit-frame-pointer"
                 }
@@ -160,9 +157,9 @@
     buildTypes {
         release {
             minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
             buildConfigField "boolean", "ENABLE_TRACE", "false"
-            consumerProguardFiles 'proguard-rules.pro'
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), useApachePackageName ? 'proguard-rules.pro' : 'proguard-rules-legacy.pro'
+            consumerProguardFiles useApachePackageName ? 'proguard-rules.pro' : 'proguard-rules-legacy.pro'
         }
 
         debug {
@@ -172,24 +169,49 @@
             testCoverageEnabled disableCov.toBoolean()
             consumerProguardFiles 'proguard-rules.pro'
         }
+
+        apacheRelease{
+            initWith release
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            consumerProguardFiles 'proguard-rules.pro'
+        }
+
+        legacyRelease{
+            initWith release
+            proguardFiles getDefaultProguardFile('proguard-android.txt'),  'proguard-rules-legacy.pro'
+            consumerProguardFiles 'proguard-rules-legacy.pro'
+        }
     }
 
     externalNativeBuild {
         cmake {
-            path '../../weex_core/CMakeLists.txt'
+            if(project.useApachePackageName) {
+                path '../../weex_core/CMakeLists.txt'
+            }
+            else{
+                copy{
+                    from new File('../../weex_core/CMakeLists.txt')
+                    into new File('src/legacyRelease/cpp')
+                }
+                path 'src/legacyRelease/cpp/CMakeLists.txt'
+            }
         }
     }
 
     sourceSets {
-        main {
-            assets.srcDirs = ['assets']
-            jniLibs.srcDir(['libs'])
-            java {
-                srcDirs = ["src/main/java"];
-            }
+        main.assets.srcDirs = ['assets']
+        apacheRelease.java.srcDirs = ['src/main/java']
+        apacheRelease.manifest.srcFile(new File('src/main/AndroidManifest.xml'))
+        legacyRelease.java.srcDirs = ['src/legacyRelease/java']
+        legacyRelease.manifest.srcFile(new File('src/legacyRelease/AndroidManifest.xml'))
+        if(!project.useApachePackageName){
+            main.java.srcDirs = ['src/legacyRelease/java']
+            main.manifest.srcFile(new File('src/legacyRelease/AndroidManifest.xml'))
         }
-        debug.setRoot('build-types/debug')
-        release.setRoot('build-types/release')
+
+        if(project.unbundlingJSC){
+            main.jniLibs.srcDirs = []
+        }
     }
 
     compileOptions.encoding = "UTF-8"
@@ -209,7 +231,6 @@
 }
 
 dependencies {
-    implementation fileTree(include: ['*.jar'], dir: 'libs')
     //noinspection GradleDependency
     compileOnly "com.android.support:recyclerview-v7:${project.supportLibVersion}"
     //noinspection GradleDependency
@@ -238,202 +259,32 @@
     testImplementation 'org.json:json:20160212'
 }
 
-if(file('../license/LICENSE').exists()){
-    license {
-        header = file('../license/LICENSE')
-        mapping('cpp','JAVADOC_STYLE')
-        mapping('h','JAVADOC_STYLE')
-        excludes(['com/taobao/weex/utils/WXDataStructureUtil.java'])
-    }
-
-    task weex_core_license(type: com.hierynomus.gradle.license.tasks.LicenseFormat){
-        source = fileTree(dir:"../../weex_core").include(['**/*.h','**/*.cpp', '**/*.cc', '**/*.c']).
-                exclude(['Source/rapidjson/**/*.h','Source/rapidjson/**/*.cpp',
-                         'Source/android/jniprebuild/jniheader/*.h',
-                         'Source/base/Compatible.cpp',
-                         'Source/IPC/**/*.h','Source/IPC/**/*.cpp', 'Source/IPC/**/*.c',
-                         'Source/base/base64/modp_base64/**/*.h',
-                         'Source/base/base64/modp_base64/**/*.cc',
-                         'Source/base/third_party/icu/*.h',
-                         'Source/base/third_party/icu/*.cpp',
-                         'Source/android/jsengine/dependence/**/*.h',
-                         'Source/android/jsengine/dependence/**/*.cpp',
-                         'Source/include/wtf/**/*.h',
-                         'Source/include/wtf/**/*.c',
-                         'Source/include/wtf/**/*.cpp',
-                         'Source/include/JavaScriptCore/**/*.h',
-                         'Source/include/JavaScriptCore/**/*.c',
-                         'Source/include/JavaScriptCore/**/*.cpp'])
-    }
-    preBuild.dependsOn licenseFormat
-}
-def ndkDir = ''
-task checkNdkVersion() {
-    def rootDir = project.rootDir
-    def localProperties = new File(rootDir, "local.properties")
-    if (localProperties.exists()) {
-        Properties properties = new Properties()
-        localProperties.withInputStream { instr ->
-            properties.load(instr)
-        }
-        ndkDir = properties.getProperty('ndk.dir')
-    }
-
-//    if(null == ndkDir){
-//        def errMsg ='please set ndk.dir path in project/local.properties and ndk-16 supported only,example: ndk.dir=/Users/xxx/Library/Android/sdk/ndk-bundle-r16'
-//        throw new StopActionException(errMsg)
-//    }
+license {
+    header = file('../license/LICENSE')
+    mapping('cpp', 'JAVADOC_STYLE')
+    mapping('h', 'JAVADOC_STYLE')
+    excludes(['org/apache/weex/utils/WXDataStructureUtil.java'])
 }
 
-preBuild.dependsOn checkNdkVersion
-
-def siteUrl = 'https://weex.incubator.apache.org'
-def gitUrl = 'https://github.com/apache/incubator-weex.git'
-group = "com.taobao.android"
-install {
-    repositories.mavenInstaller {
-        // This generates POM.xml with proper parameters
-        pom {
-            project {
-                packaging 'aar'
-                name 'weex_sdk'
-                url siteUrl
-                licenses {
-                    license {
-                        name 'The Apache Software License, Version 2.0'
-                        url 'https://www.apache.org/licenses/LICENSE-2.0.txt'
-                    }
-                }
-                developers {
-                    developer {
-                        id 'weex alibaba'
-                        name 'weex alibaba'
-                        email 'alibabaweex@gmail.com'
-                    }
-                }
-                scm {
-                    connection gitUrl
-                    developerConnection gitUrl
-                    url siteUrl
-                }
-            }
-        }
-    }
+task weex_core_license(type: com.hierynomus.gradle.license.tasks.LicenseFormat) {
+    source = fileTree(dir: "../../weex_core").include(['**/*.h', '**/*.cpp', '**/*.cc', '**/*.c']).
+            exclude(['Source/rapidjson/**/*.h', 'Source/rapidjson/**/*.cpp',
+                     'Source/android/jniprebuild/jniheader/*.h',
+                     'Source/base/Compatible.cpp',
+                     'Source/IPC/**/*.h', 'Source/IPC/**/*.cpp', 'Source/IPC/**/*.c',
+                     'Source/base/base64/modp_base64/**/*.h',
+                     'Source/base/base64/modp_base64/**/*.cc',
+                     'Source/base/third_party/icu/*.h',
+                     'Source/base/third_party/icu/*.cpp',
+                     'Source/android/jsengine/dependence/**/*.h',
+                     'Source/android/jsengine/dependence/**/*.cpp',
+                     'Source/include/wtf/**/*.h',
+                     'Source/include/wtf/**/*.c',
+                     'Source/include/wtf/**/*.cpp',
+                     'Source/include/JavaScriptCore/**/*.h',
+                     'Source/include/JavaScriptCore/**/*.c',
+                     'Source/include/JavaScriptCore/**/*.cpp'])
 }
 
-task sourcesJar(type: Jar) {
-    from android.sourceSets.main.java.srcDirs
-    classifier = 'sources'
-}
-
-artifacts {
-    archives sourcesJar
-}
-
-bintray {
-    configurations = ['archives']
-    user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
-    key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
-    pkg {
-        repo = "maven"
-        name = "weex_sdk"
-        websiteUrl = siteUrl
-        vcsUrl = gitUrl
-        licenses = ["Apache-2.0"]
-        publish = true
-        version {
-            //The version to be published
-            name = project.version
-            vcsTag = project.version
-        }
-    }
-}
-artifactory {
-    contextUrl = 'http://oss.jfrog.org/artifactory'
-    publish {
-        repository {
-            repoKey = 'oss-snapshot-local'
-            username = bintray.user
-            password = bintray.key
-            maven = true
-        }
-        defaults {
-            publishConfigs('archives')
-        }
-    }
-}
-def asanAbi = project.hasProperty('asanAbi') ? project.getProperty('asanAbi') : 'arm64-v8a'
-task clearASanLibs(type: Delete){
-    delete project.android.sourceSets.main.resources.srcDirs
-    delete fileTree(project.android.sourceSets.main.jniLibs.srcDirs[-1]) {
-        include '**/libclang_rt.asan-*-android.so'
-    }
-}
-task copyWrapScript(type: Copy,dependsOn: clearASanLibs) {
-    if(project.hasProperty('enableASan') && "true" == project.getProperty('enableASan')) {
-        from 'wrap.sh'
-        into new File(project.android.sourceSets.main.resources.srcDirs[-1], "lib")
-        eachFile {
-            it.path = "${asanAbi}/${it.name}"
-        }
-    }
-}
-task copyASanLib(type: Copy,dependsOn: copyWrapScript){
-    if(project.hasProperty('enableASan') && "true" == project.getProperty('enableASan')) {
-        def ndkPath = ndkDir == '' ? System.getenv("ANDROID_NDK_HOME"):ndkDir
-        def dir = ndkPath + '/toolchains/llvm/prebuilt/'
-        def renamedAbi = asanAbi
-        if (asanAbi == "armeabi-v7a" || asanAbi == "armeabi")
-            renamedAbi = "arm"
-        if (asanAbi == "arm64-v8a")
-            renamedAbi = "aarch64"
-        if (asanAbi == "x86")
-            renamedAbi = "i686"
-        new File(dir).eachFileRecurse { file ->
-            if (file.name == 'libclang_rt.asan-' + renamedAbi + '-android.so')
-                from file.absolutePath
-                into project.android.sourceSets.main.jniLibs.srcDirs[-1]
-                eachFile {
-                    it.path = "${asanAbi}/${it.name}"
-                }
-            includeEmptyDirs = false
-        }
-    }
-}
-preBuild.dependsOn copyASanLib
-
-afterEvaluate { project ->
-    transformNativeLibsWithStripDebugSymbolForRelease << {
-        copy{
-            from transformNativeLibsWithMergeJniLibsForRelease
-            into new File(project.buildDir, "unstrippedSo")
-            include '**/libweexjss.so', '**/libweexcore.so'
-            eachFile {
-                it.path = "${it.relativePath.segments[-2]}_${it.name}"
-            }
-        }
-
-        if(project.hasProperty('supportArmeabi') && "true" == project.getProperty('supportArmeabi')){
-            //Copy stripped shared library from armeabi-v7a into armeabi
-            copy{
-                from transformNativeLibsWithStripDebugSymbolForRelease
-                into project.android.sourceSets.main.jniLibs.srcDirs[-1]
-                include '**/armeabi-v7a/**'
-                exclude '**/libc++_shared.so'
-                eachFile {
-                    it.path = "armeabi/${it.name}"
-                }
-            }
-
-            //Copy Unstripped shared library from armeabi-v7a into armeabi
-            copy{
-                from transformNativeLibsWithMergeJniLibsForRelease
-                into new File(project.buildDir, "unstrippedSo")
-                include '**/armeabi-v7a/libweexjss.so', '**/armeabi-v7a/libweexcore.so'
-                eachFile {
-                    it.path = "armeabi_${it.name}"
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
+preBuild.dependsOn licenseFormat, copyJSCHeaderToWeexCore
+clean.dependsOn cleanCopyJSCHeaderToWeexCore
\ No newline at end of file
diff --git a/android/sdk/buildSrc/asan.gradle b/android/sdk/buildSrc/asan.gradle
new file mode 100644
index 0000000..df81979
--- /dev/null
+++ b/android/sdk/buildSrc/asan.gradle
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+def asanAbi = project.hasProperty('asanAbi') ? project.getProperty('asanAbi') : 'arm64-v8a'
+def ndkDir = ''
+
+task checkNdkVersion() {
+    def rootDir = project.rootDir
+    def localProperties = new File(rootDir, "local.properties")
+    if (localProperties.exists()) {
+        Properties properties = new Properties()
+        localProperties.withInputStream { instr ->
+            properties.load(instr)
+        }
+        ndkDir = properties.getProperty('ndk.dir')
+    }
+}
+
+task clearASanLibs(type: Delete){
+    delete project.android.sourceSets.main.resources.srcDirs
+    delete fileTree(project.android.sourceSets.main.jniLibs.srcDirs[-1]) {
+        include '**/libclang_rt.asan-*-android.so'
+    }
+}
+task copyWrapScript(type: Copy,dependsOn: clearASanLibs) {
+    if(project.hasProperty('enableASan') && "true" == project.getProperty('enableASan')) {
+        from 'wrap.sh'
+        into new File(project.android.sourceSets.main.resources.srcDirs[-1], "lib")
+        eachFile {
+            it.path = "${asanAbi}/${it.name}"
+        }
+    }
+}
+task copyASanLib(type: Copy){
+    dependsOn copyWrapScript, copyJscToJniDir
+    if(project.hasProperty('enableASan') && "true" == project.getProperty('enableASan')) {
+        def ndkPath = ndkDir == '' ? System.getenv("ANDROID_NDK_HOME"):ndkDir
+        def dir = ndkPath + '/toolchains/llvm/prebuilt/'
+        def renamedAbi = asanAbi
+        if (asanAbi == "armeabi-v7a" || asanAbi == "armeabi")
+            renamedAbi = "arm"
+        if (asanAbi == "arm64-v8a")
+            renamedAbi = "aarch64"
+        if (asanAbi == "x86")
+            renamedAbi = "i686"
+        new File(dir).eachFileRecurse { file ->
+            if (file.name == 'libclang_rt.asan-' + renamedAbi + '-android.so')
+                from file.absolutePath
+            into project.android.sourceSets.main.jniLibs.srcDirs[-1]
+            eachFile {
+                it.path = "${asanAbi}/${it.name}"
+            }
+            includeEmptyDirs = false
+        }
+    }
+}
+
+preBuild.dependsOn copyASanLib, checkNdkVersion
\ No newline at end of file
diff --git a/android/sdk/buildSrc/checkStyle.gradle b/android/sdk/buildSrc/checkStyle.gradle
new file mode 100644
index 0000000..2df40e0
--- /dev/null
+++ b/android/sdk/buildSrc/checkStyle.gradle
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+task checkstyle(type: Checkstyle) {
+    configFile file("${project.rootDir}/sdk/config/quality/checkstyle.xml") // Where my checkstyle config is...
+    // configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/config/quality/checkstyle/suppressions.xml").absolutePath // Where is my suppressions file for checkstyle is...
+    source 'src'
+    include '**/*.java'
+    exclude '**/gen/**'
+    exclude '**/test/**'
+    exclude '**/com/taobao/weex/dom/flex/**'
+    classpath = files()
+}
+
+checkstyle {
+    toolVersion = '6.9'
+}
\ No newline at end of file
diff --git a/android/sdk/buildSrc/download_jsc.gradle b/android/sdk/buildSrc/download_jsc.gradle
new file mode 100644
index 0000000..c75c90e
--- /dev/null
+++ b/android/sdk/buildSrc/download_jsc.gradle
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+def jsc_dir = new File(project.buildDir, 'jsc')
+def jsc_url = project.hasProperty('jsc_url') ? new URL(project.getProperty('jsc_url').toString()) : new URL('https://registry.npmjs.org/jsc-android/-/jsc-android-241213.1.0.tgz')
+def aar_name = project.hasProperty('aar_name') ? project.getProperty('aar_name').toString() : 'android-jsc-intl'
+
+def jsc_file = new File(jsc_dir, jsc_url.path.split('/').last())
+def aar_file = new File(jsc_dir, "${aar_name}.aar")
+
+def downloadJSC = { URL url, File dest ->
+    if (!dest.getParentFile().exists()) {
+        dest.getParentFile().mkdirs()
+    }
+    url.withInputStream { i -> dest.withOutputStream { it << i } }
+}
+
+task download(){
+    inputs.property('url', jsc_url)
+    outputs.file(jsc_file)
+    outputs.upToDateWhen {
+        jsc_file.exists()
+    }
+    doFirst {
+        if (!jsc_file.exists()) {
+            downloadJSC(jsc_url, jsc_file)
+        }
+    }
+}
+
+task unzipJSC(type: Copy, dependsOn: download) {
+    from jsc_file.name.endsWith(".aar") ? jsc_file : tarTree(jsc_file)
+    into jsc_dir
+    include "**/*${aar_name}*.aar", '**/include/*.h'
+    includeEmptyDirs false
+    eachFile {
+        if(it.name.endsWith('.aar')) {
+            it.path = it.name
+            it.name = "${aar_name}.aar"
+        }
+        else if(it.name.endsWith('.h')){
+            it.path= 'include/' + it.name
+        }
+    }
+    inputs.file(jsc_file)
+    outputs.file(aar_file)
+    outputs.upToDateWhen {
+        aar_file.exists()
+    }
+}
+
+task copyJscToJniDir(type: Copy, dependsOn: unzipJSC) {
+    def libsDir = project.android.sourceSets.main.jniLibs.srcDirs[-1]
+    from zipTree(aar_file)
+    into libsDir
+    include 'jni/**/*.so'
+    exclude '**/libweexcore.so', '**/libweexjsb.so', '**/libweexjss.so',
+            '**/libweexjssr.so', '**/libweexjst.so', '**/libc++_shared.so',
+            '**/x86_64/**'
+    includeEmptyDirs false
+    eachFile {
+        def path_list = new LinkedList<>(it.relativePath.segments.toList())
+        path_list.removeAt(0)
+        it.relativePath = new RelativePath(true, path_list[0], path_list[1])
+    }
+    inputs.file(aar_file)
+    outputs.upToDateWhen {false}
+}
+
+task copyJSCHeaderToWeexCore(type: Copy, dependsOn: unzipJSC) {
+    from new File(jsc_dir, 'include')
+    into '../../weex_core/Source/include/JSCHeaderNew/JavaScriptCore'
+    includeEmptyDirs false
+    inputs.dir(new File(jsc_dir, 'include'))
+}
+
+preBuild.dependsOn copyJscToJniDir
+clean.dependsOn cleanCopyJscToJniDir
\ No newline at end of file
diff --git a/android/sdk/buildSrc/jcenter.gradle b/android/sdk/buildSrc/jcenter.gradle
new file mode 100644
index 0000000..fb8b55a
--- /dev/null
+++ b/android/sdk/buildSrc/jcenter.gradle
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+def siteUrl = 'https://weex.apache.org/'
+def gitUrl = 'https://github.com/apache/incubator-weex.git'
+def mailingList = 'dev@weex.apache.org'
+def description='Apache Weex is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.All Apache Weex releases are in the form of source code, binary/bytecode packages are produced as a convenience to users. View https://weex.apache.org/download/download.html for official Apache Release.'
+install {
+    repositories.mavenInstaller {
+        // This generates POM.xml with proper parameters
+        pom {
+            project {
+                packaging 'aar'
+                name 'Apache Incubator-Weex'
+                artifactId project.artifactName
+                groupId project.groupId
+                url siteUrl
+                version = project.weexVersion
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'https://raw.githubusercontent.com/apache/incubator-weex/master/LICENSE'
+                    }
+                }
+                developers {
+                    developer {
+                        name 'Apache Weex PPMC'
+                        email mailingList
+                    }
+                }
+                scm {
+                    connection gitUrl
+                    developerConnection mailingList
+                    url siteUrl
+                }
+            }
+        }
+    }
+}
+
+bintray {
+    configurations = ['archives']
+    user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
+    key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
+    pkg {
+        repo = 'Android'
+        name = project.artifactName
+        websiteUrl = siteUrl
+        desc = description
+        vcsUrl = gitUrl
+        licenses = ["Apache-2.0"]
+        publish = true
+        version {
+            desc = description
+            released = new Date()
+            name = project.weexVersion
+            vcsTag = project.hasProperty('vcsTag') ? project.property('vcsTag') :  project.weexVersion
+        }
+    }
+}
+
+task sourcesJar(type: Jar) {
+    from android.sourceSets.main.java.srcDirs
+    classifier = 'sources'
+}
+
+artifacts {
+    archives sourcesJar
+}
+
+if (project.gradle.startParameter.taskNames.contains('artifactoryPublish') ||
+        project.gradle.startParameter.taskNames.contains(':weex_sdk:artifactoryPublish')) {
+    apply plugin: 'maven-publish'
+    publishing {
+        publications {
+            artifactorySnapthost(MavenPublication) {
+                groupId project.groupId
+                artifactId project.artifactName
+                version project.weexVersion
+                artifact bundleReleaseAar
+            }
+        }
+        repositories {
+            maven {
+                name = 'OJOSnapshot'
+                url = 'http://oss.jfrog.org/artifactory'
+            }
+        }
+    }
+}
+
+artifactory {
+    contextUrl = 'http://oss.jfrog.org/artifactory'
+    publish {
+        repository {
+            repoKey = 'oss-snapshot-local'
+            username = bintray.user
+            password = bintray.key
+            maven = true
+        }
+        defaults {
+            publications ('artifactorySnapthost')
+        }
+    }
+}
\ No newline at end of file
diff --git a/android/sdk/buildSrc/packageName.gradle b/android/sdk/buildSrc/packageName.gradle
new file mode 100644
index 0000000..232c30d
--- /dev/null
+++ b/android/sdk/buildSrc/packageName.gradle
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+task copyAndRenamePackage(type: Copy) {
+    if(!project.useApachePackageName) {
+        inputs.dir new File('src/main/java/org/apache/weex')
+        from new File('src/main/java/org/apache/weex')
+        into new File('src/legacyRelease/java/com/taobao/weex')
+        filter { String line ->
+            line.replaceAll(/^(package org\.apache)(\.weex.*)$/, { _, packageName, suffix ->
+                "package com.taobao${suffix}"
+            }).replaceAll(/^(import org\.apache)(\.weex.*)$/, { _, packageName, suffix ->
+                "import com.taobao${suffix}"
+            }).replaceAll(/^(import static org\.apache)(\.weex.*)$/, { _, packageName, suffix ->
+                "import static com.taobao${suffix}"
+            })
+        }
+    }
+}
+
+task copyManifest(type: Copy){
+    if(!project.useApachePackageName){
+        inputs.file new File('src/main/AndroidManifest.xml')
+        from new File('src/main/AndroidManifest.xml')
+        into new File('src/legacyRelease')
+        filter { String line ->
+            line.replaceAll(/(org\.apache)(\.weex.*)/, { _, packageName, suffix ->
+                "com.taobao${suffix}"
+            })
+        }
+    }
+}
+
+task copyProguard(type: Copy){
+    if(!project.useApachePackageName){
+        inputs.file new File('proguard-rules.pro')
+        from new File('proguard-rules.pro')
+        into new File('.')
+        rename 'proguard-rules.pro', 'proguard-rules-legacy.pro'
+        filter { String line ->
+            line.replaceAll(/(org\.apache)(\.weex.*)/, { _, packageName, suffix ->
+                "com.taobao${suffix}"
+            })
+        }
+    }
+}
+
+task(cleanCopyProguard, overwrite: true, type: Delete){
+    delete 'proguard-rules-legacy.pro'
+}
+
+task copyOtherCppFile(type: Copy){
+    if(!project.useApachePackageName) {
+        inputs.dir new File('../../weex_core')
+        from new File('../../weex_core')
+        into new File('src/legacyRelease/cpp')
+        exclude '**/*.cpp', '**/*.cc', '**/*.c', '**/*.h', '**/*.hpp'
+    }
+}
+
+task copyAndRenameCppSourceFile(type: Copy){
+    dependsOn copyOtherCppFile, copyJSCHeaderToWeexCore
+    if(!project.useApachePackageName) {
+        inputs.dir new File('../../weex_core')
+        from new File('../../weex_core')
+        into new File('src/legacyRelease/cpp')
+        include '**/*.cpp', '**/*.cc', '**/*.c', '**/*.h', '**/*.hpp'
+        filter { String line ->
+            line.replaceAll('(.*".*)(org/apache/weex)(.*".*)', { _, prefix, packageName, suffix ->
+                logger.info("Content substation in .cpp/.h files happpened, \n Input: ${line}, \n Output: ${prefix}com/taobao/weex${suffix}")
+                "${prefix}com/taobao/weex${suffix}"
+            })
+        }
+    }
+}
+
+gradle.taskGraph.beforeTask { Task task ->
+    if(task.name == 'assembleApacheRelease'){
+        throw new StopActionException('Not Supported. assembleApacheRelease is not supported, please use the following command instead.\n assembleRelease -PapachePackageName="true"')
+    }
+    else if(task.name == 'assembleLegacyRelease'){
+        throw new StopActionException('Not Supported. assembleLegacyRelease is not supported, please use the following command instead.\n assembleRelease -PapachePackageName="false"')
+    }
+}
+
+preBuild.dependsOn copyAndRenameCppSourceFile, copyAndRenamePackage, copyManifest, copyProguard
+clean.dependsOn cleanCopyAndRenamePackage, cleanCopyManifest, cleanCopyProguard, cleanCopyOtherCppFile, cleanCopyAndRenameCppSourceFile
\ No newline at end of file
diff --git a/android/sdk/buildSrc/unstripped.gradle b/android/sdk/buildSrc/unstripped.gradle
new file mode 100644
index 0000000..8a22ee0
--- /dev/null
+++ b/android/sdk/buildSrc/unstripped.gradle
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+def processNativeLibs = { unstripped, stripped ->
+    copy{
+        from unstripped
+        into new File(project.buildDir, "unstrippedSo")
+        include '**/libweexjss.so', '**/libweexcore.so'
+        eachFile {
+            it.path = "${it.relativePath.segments[-2]}_${it.name}"
+        }
+    }
+
+    if(project.hasProperty('supportArmeabi') && "true" == project.getProperty('supportArmeabi')){
+        //Copy stripped shared library from armeabi-v7a into armeabi
+        copy{
+            from stripped
+            into project.android.sourceSets.main.jniLibs.srcDirs[-1]
+            include '**/armeabi-v7a/**'
+            exclude '**/libc++_shared.so'
+            eachFile {
+                it.path = "armeabi/${it.name}"
+            }
+        }
+
+        //Copy Unstripped shared library from armeabi-v7a into armeabi
+        copy{
+            from unstripped
+            into new File(project.buildDir, "unstrippedSo")
+            include '**/armeabi-v7a/libweexjss.so', '**/armeabi-v7a/libweexcore.so'
+            eachFile {
+                it.path = "armeabi_${it.name}"
+            }
+        }
+    }
+}
+
+afterEvaluate { project ->
+    transformNativeLibsWithStripDebugSymbolForRelease.doLast {
+        processNativeLibs transformNativeLibsWithMergeJniLibsForRelease,
+                transformNativeLibsWithStripDebugSymbolForRelease
+    }
+
+    transformNativeLibsWithStripDebugSymbolForApacheRelease.doLast {
+        processNativeLibs transformNativeLibsWithMergeJniLibsForApacheRelease,
+                transformNativeLibsWithStripDebugSymbolForApacheRelease
+    }
+
+    transformNativeLibsWithStripDebugSymbolForLegacyRelease.doLast {
+        processNativeLibs transformNativeLibsWithMergeJniLibsForLegacyRelease,
+                transformNativeLibsWithStripDebugSymbolForLegacyRelease
+    }
+}
\ No newline at end of file
diff --git a/android/sdk/build_jss_r.sh b/android/sdk/build_jss_r.sh
index 7334cd3..cf0a5a0 100755
--- a/android/sdk/build_jss_r.sh
+++ b/android/sdk/build_jss_r.sh
@@ -1,3 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
 echo "--> # buils jsc_runtime so"
 
 
diff --git a/android/sdk/libs/arm64-v8a/libJavaScriptCore.so b/android/sdk/libs/arm64-v8a/libJavaScriptCore.so
deleted file mode 100755
index 7f33280..0000000
--- a/android/sdk/libs/arm64-v8a/libJavaScriptCore.so
+++ /dev/null
Binary files differ
diff --git a/android/sdk/libs/arm64-v8a/libWTF.so b/android/sdk/libs/arm64-v8a/libWTF.so
deleted file mode 100755
index ce8d0bc..0000000
--- a/android/sdk/libs/arm64-v8a/libWTF.so
+++ /dev/null
Binary files differ
diff --git a/android/sdk/libs/armeabi-v7a/libJavaScriptCore.so b/android/sdk/libs/armeabi-v7a/libJavaScriptCore.so
deleted file mode 100755
index d6b471c..0000000
--- a/android/sdk/libs/armeabi-v7a/libJavaScriptCore.so
+++ /dev/null
Binary files differ
diff --git a/android/sdk/libs/armeabi-v7a/libWTF.so b/android/sdk/libs/armeabi-v7a/libWTF.so
deleted file mode 100755
index 790bef2..0000000
--- a/android/sdk/libs/armeabi-v7a/libWTF.so
+++ /dev/null
Binary files differ
diff --git a/android/sdk/libs/x86/libJavaScriptCore.so b/android/sdk/libs/x86/libJavaScriptCore.so
deleted file mode 100755
index 3cdfd01..0000000
--- a/android/sdk/libs/x86/libJavaScriptCore.so
+++ /dev/null
Binary files differ
diff --git a/android/sdk/libs/x86/libWTF.so b/android/sdk/libs/x86/libWTF.so
deleted file mode 100755
index 6d2bb48..0000000
--- a/android/sdk/libs/x86/libWTF.so
+++ /dev/null
Binary files differ
diff --git a/android/sdk/lint.xml b/android/sdk/lint.xml
index 747992e..6a2cf16 100644
--- a/android/sdk/lint.xml
+++ b/android/sdk/lint.xml
@@ -1,4 +1,22 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
 <lint>
   <!-- Ignore the UselessLeaf issue in the specified file -->
   <issue id="IconLocation">
diff --git a/android/sdk/proguard-rules.pro b/android/sdk/proguard-rules.pro
index 957227f..19b57c0 100755
--- a/android/sdk/proguard-rules.pro
+++ b/android/sdk/proguard-rules.pro
@@ -34,8 +34,8 @@
 #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
 #   public *;
 #}
--keep class com.taobao.weex.bridge.** { *; }
--keep class com.taobao.weex.layout.** { *; }
--keep class com.taobao.weex.WXSDKEngine { *; }
--keep class com.taobao.weex.base.SystemMessageHandler { *; }
--dontwarn com.taobao.weex.bridge.**
+-keep class org.apache.weex.bridge.** { *; }
+-keep class org.apache.weex.layout.** { *; }
+-keep class org.apache.weex.WXSDKEngine { *; }
+-keep class org.apache.weex.base.SystemMessageHandler { *; }
+-dontwarn org.apache.weex.bridge.**
diff --git a/android/sdk/src/main/AndroidManifest.xml b/android/sdk/src/main/AndroidManifest.xml
index 5360c0c..3c06bb4 100755
--- a/android/sdk/src/main/AndroidManifest.xml
+++ b/android/sdk/src/main/AndroidManifest.xml
@@ -18,6 +18,6 @@
 under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.taobao.weex">
+          package="org.apache.weex">
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 </manifest>
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/ComponentObserver.java b/android/sdk/src/main/java/com/taobao/weex/ComponentObserver.java
deleted file mode 100644
index a2bcd09..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ComponentObserver.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.view.View;
-
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by sospartan on 14/06/2017.
- */
-
-public interface ComponentObserver {
-
-  /**
-   * Called after component is create.
-   * Notice: View is not created at this moment.
-   * @param component
-   */
-  void onCreate(WXComponent component);
-
-  /**
-   * Called before component destroy.
-   * @param component
-   */
-  void onPreDestory(WXComponent component);
-
-  /**
-   * Called when component's view is created
-   * @param component
-   * @param view
-   */
-  void onViewCreated(WXComponent component,View view);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/IWXActivityStateListener.java b/android/sdk/src/main/java/com/taobao/weex/IWXActivityStateListener.java
deleted file mode 100644
index cc2d413..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/IWXActivityStateListener.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-/**
- * Listener class for activity lifecycle
- */
-
-@Deprecated
-public interface IWXActivityStateListener {
-
-  void onActivityCreate();
-
-  void onActivityStart();
-
-  void onActivityPause();
-
-  void onActivityResume();
-
-  void onActivityStop();
-
-  void onActivityDestroy();
-
-  boolean onActivityBack();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/IWXRenderListener.java b/android/sdk/src/main/java/com/taobao/weex/IWXRenderListener.java
deleted file mode 100644
index fd78d60..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/IWXRenderListener.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.view.View;
-
-public interface IWXRenderListener {
-
-  /**
-   * If {@link com.taobao.weex.common.WXRenderStrategy#APPEND_ASYNC} is applied, this method
-   * will be invoked when the rendering of first view is finish.
-   * If {@link com.taobao.weex.common.WXRenderStrategy#APPEND_ONCE} is applied, this method will
-   * be invoked when the rendering of the view tree is finished.
-   */
-  void onViewCreated(WXSDKInstance instance, View view);
-
-  /**
-   * Called when the render view phase of weex has finished.
-   * It can be invoked at most once in the entire life of a {@link WXSDKInstance}
-   */
-  void onRenderSuccess(WXSDKInstance instance, int width, int height);
-
-  /**
-   * Callback method, called when refresh is finished
-   */
-  void onRefreshSuccess(WXSDKInstance instance, int width, int height);
-
-  /**
-   * Report exception occurred when weex instance is running. Exception <strong>may not</strong>
-   * cause user-noticeable failure of weex.
-   */
-  void onException(WXSDKInstance instance, String errCode, String msg);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/IWXStatisticsListener.java b/android/sdk/src/main/java/com/taobao/weex/IWXStatisticsListener.java
deleted file mode 100644
index 814edae..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/IWXStatisticsListener.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-public interface IWXStatisticsListener {
-  /**
-   * Called when weex sdk engine begin to initialize.
-   */
-   void onSDKEngineInitialize();
-
-  /**
-   * Called when begin to load js framework.
-   */
-   void onJsFrameworkStart();
-
-  /**
-   * Called when finish loading js framework.
-   */
-   void onJsFrameworkReady();
-
-  /**
-   * Called when the render view phase of first view reached.
-   */
-   void onFirstView();
-
-  /**
-   * Called when the render view phase of first screen reached.
-   */
-  void onFirstScreen();
-
-  /**
-   * Called when to start a http request.
-   */
-  void onHttpStart();
-
-  /**
-   * Called when received a http response header data.
-   */
-  void onHeadersReceived();
-
-  /**
-   * Called when to finish a http request.
-   */
-  void onHttpFinish();
-
-  /**
-   * Called when an exception occured.
-   */
-  void onException(String instanceid, String errCode, String msg);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/InitConfig.java b/android/sdk/src/main/java/com/taobao/weex/InitConfig.java
deleted file mode 100644
index 053fb82..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/InitConfig.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.support.annotation.NonNull;
-import com.taobao.weex.adapter.ClassLoaderAdapter;
-import com.taobao.weex.adapter.IDrawableLoader;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.adapter.IWXImgLoaderAdapter;
-import com.taobao.weex.adapter.IWXJSExceptionAdapter;
-import com.taobao.weex.adapter.IWXJsFileLoaderAdapter;
-import com.taobao.weex.adapter.IWXJscProcessManager;
-import com.taobao.weex.adapter.IWXSoLoaderAdapter;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.appfram.storage.IWXStorageAdapter;
-import com.taobao.weex.appfram.websocket.IWebSocketAdapterFactory;
-import com.taobao.weex.performance.IApmGenerator;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Created by sospartan on 5/31/16.
- */
-public class InitConfig {
-  private IWXHttpAdapter httpAdapter;
-  private IDrawableLoader drawableLoader;
-  private IWXImgLoaderAdapter imgAdapter;
-  private IWXUserTrackAdapter utAdapter;
-  private IWXStorageAdapter storageAdapter;
-  private IWXSoLoaderAdapter soLoader;
-  private URIAdapter mURIAdapter;
-  private IWebSocketAdapterFactory webSocketAdapterFactory;
-  private IWXJSExceptionAdapter mJSExceptionAdapter;
-  private String framework;
-  private ClassLoaderAdapter classLoaderAdapter;
-  private IApmGenerator apmGenerater;
-  private IWXJsFileLoaderAdapter jsFileLoaderAdapter;
-  private IWXJscProcessManager jscProcessManager;
-  private List<String> nativeLibraryList;
-
-  public IWXHttpAdapter getHttpAdapter() {
-    return httpAdapter;
-  }
-
-  public IWXImgLoaderAdapter getImgAdapter() {
-    return imgAdapter;
-  }
-
-  public IDrawableLoader getDrawableLoader() {
-    return drawableLoader;
-  }
-
-  public IWXUserTrackAdapter getUtAdapter() {
-    return utAdapter;
-  }
-
-  public IWXSoLoaderAdapter getIWXSoLoaderAdapter() {
-    return soLoader;
-  }
-
-  public String getFramework() {
-    return framework;
-  }
-
-  public IWXStorageAdapter getStorageAdapter() {
-    return storageAdapter;
-  }
-
-  public URIAdapter getURIAdapter() {
-    return mURIAdapter;
-  }
-
-  public IWebSocketAdapterFactory getWebSocketAdapterFactory() {
-    return webSocketAdapterFactory;
-  }
-
-  public ClassLoaderAdapter getClassLoaderAdapter() {
-    return classLoaderAdapter;
-  }
-
-  public IApmGenerator getApmGenerater() {
-    return apmGenerater;
-  }
-
-  public IWXJsFileLoaderAdapter getJsFileLoaderAdapter() {
-    return jsFileLoaderAdapter;
-  }
-
-  public InitConfig setClassLoaderAdapter(ClassLoaderAdapter classLoaderAdapter) {
-    this.classLoaderAdapter = classLoaderAdapter;
-    return this;
-  }
-
-  public IWXJSExceptionAdapter getJSExceptionAdapter() {
-    return mJSExceptionAdapter;
-  }
-  public IWXJscProcessManager getJscProcessManager() {
-    return jscProcessManager;
-  }
-
-  @NonNull Iterable<String> getNativeLibraryList() {
-    if(nativeLibraryList == null){
-      nativeLibraryList = new LinkedList<>();
-    }
-    return nativeLibraryList;
-  }
-
-  private InitConfig() {
-  }
-
-  public static class Builder{
-    IWXHttpAdapter httpAdapter;
-    IWXImgLoaderAdapter imgAdapter;
-    IDrawableLoader drawableLoader;
-    IWXUserTrackAdapter utAdapter;
-    IWXStorageAdapter storageAdapter;
-    IWXSoLoaderAdapter soLoader;
-    URIAdapter mURIAdapter;
-    IWXJSExceptionAdapter mJSExceptionAdapter;
-    String framework;
-    IWebSocketAdapterFactory webSocketAdapterFactory;
-    ClassLoaderAdapter classLoaderAdapter;
-    IApmGenerator apmGenerater;
-    private IWXJsFileLoaderAdapter jsFileLoaderAdapter;
-    private List<String> nativeLibraryList = new LinkedList<>();
-
-    public IWXJscProcessManager getJscProcessManager() {
-      return jscProcessManager;
-    }
-
-    public Builder setJscProcessManager(IWXJscProcessManager jscProcessManager) {
-      this.jscProcessManager = jscProcessManager;
-      return this;
-    }
-
-    IWXJscProcessManager jscProcessManager;
-
-    public Builder(){
-
-    }
-
-    public Builder setHttpAdapter(IWXHttpAdapter httpAdapter) {
-      this.httpAdapter = httpAdapter;
-      return this;
-    }
-
-    public Builder setImgAdapter(IWXImgLoaderAdapter imgAdapter) {
-      this.imgAdapter = imgAdapter;
-      return this;
-    }
-
-    public Builder setDrawableLoader(IDrawableLoader drawableLoader){
-      this.drawableLoader=drawableLoader;
-      return this;
-    }
-
-    public Builder setUtAdapter(IWXUserTrackAdapter utAdapter) {
-      this.utAdapter = utAdapter;
-      return this;
-    }
-
-    public Builder setStorageAdapter(IWXStorageAdapter storageAdapter) {
-      this.storageAdapter = storageAdapter;
-      return this;
-    }
-
-    public Builder setURIAdapter(URIAdapter URIAdapter) {
-      mURIAdapter = URIAdapter;
-      return this;
-    }
-
-    public Builder setJSExceptionAdapter(IWXJSExceptionAdapter JSExceptionAdapter) {
-      mJSExceptionAdapter = JSExceptionAdapter;
-      return this;
-    }
-
-    public Builder setSoLoader(IWXSoLoaderAdapter loader) {
-      this.soLoader = loader;
-      return this;
-    }
-
-    public Builder setFramework(String framework){
-      this.framework=framework;
-      return this;
-    }
-
-    public Builder setWebSocketAdapterFactory(IWebSocketAdapterFactory factory) {
-      this.webSocketAdapterFactory = factory;
-      return this;
-    }
-
-    public Builder setClassLoaderAdapter(ClassLoaderAdapter classLoaderAdapter) {
-      this.classLoaderAdapter = classLoaderAdapter;
-      return this;
-    }
-
-    public Builder setApmGenerater(IApmGenerator apmGenerater){
-      this.apmGenerater =apmGenerater;
-      return this;
-    }
-
-    public Builder setJsFileLoaderAdapter(IWXJsFileLoaderAdapter jsFileLoaderAdapter) {
-      this.jsFileLoaderAdapter = jsFileLoaderAdapter;
-      return this;
-    }
-
-    public Builder addNativeLibrary(String name){
-      nativeLibraryList.add(name);
-      return this;
-    }
-
-    public InitConfig build(){
-      InitConfig config =  new InitConfig();
-      config.httpAdapter = this.httpAdapter;
-      config.imgAdapter = this.imgAdapter;
-      config.drawableLoader = this.drawableLoader;
-      config.utAdapter = this.utAdapter;
-      config.storageAdapter = this.storageAdapter;
-      config.soLoader=this.soLoader;
-      config.framework=this.framework;
-      config.mURIAdapter = this.mURIAdapter;
-      config.webSocketAdapterFactory = this.webSocketAdapterFactory;
-      config.mJSExceptionAdapter=this.mJSExceptionAdapter;
-      config.classLoaderAdapter = this.classLoaderAdapter;
-      config.apmGenerater = this.apmGenerater;
-      config.jsFileLoaderAdapter = this.jsFileLoaderAdapter;
-      config.jscProcessManager = this.jscProcessManager;
-      config.nativeLibraryList = this.nativeLibraryList;
-      return config;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/RenderContainer.java b/android/sdk/src/main/java/com/taobao/weex/RenderContainer.java
deleted file mode 100644
index cec6eaf..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/RenderContainer.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.view.View;
-
-
-import com.taobao.weex.render.WXAbstractRenderContainer;
-
-/**
- * Created by sospartan on 08/10/2016.
- */
-
-public class RenderContainer extends WXAbstractRenderContainer implements WeexFrameRateControl.VSyncListener{
-  private WeexFrameRateControl mFrameRateControl;
-
-  public RenderContainer(Context context) {
-    super(context);
-    mFrameRateControl = new WeexFrameRateControl(this);
-  }
-
-  public RenderContainer(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    mFrameRateControl = new WeexFrameRateControl(this);
-  }
-
-  public RenderContainer(Context context, AttributeSet attrs, int defStyleAttr) {
-    super(context, attrs, defStyleAttr);
-    mFrameRateControl = new WeexFrameRateControl(this);
-  }
-
-  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-  public RenderContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-    super(context, attrs, defStyleAttr, defStyleRes);
-    mFrameRateControl = new WeexFrameRateControl(this);
-  }
-
-
-
-  @Override
-  public void onAttachedToWindow() {
-    super.onAttachedToWindow();
-    if (mFrameRateControl != null) {
-      mFrameRateControl.start();
-    }
-  }
-
-  @Override
-  protected void onDetachedFromWindow() {
-    super.onDetachedFromWindow();
-    if (mFrameRateControl != null) {
-      mFrameRateControl.stop();
-    }
-  }
-  @Override
-  public void dispatchWindowVisibilityChanged(int visibility) {
-    super.dispatchWindowVisibilityChanged(visibility);
-    if (visibility == View.GONE) {
-      if (mFrameRateControl != null) {
-        mFrameRateControl.stop();
-      }
-    } else if (visibility == View.VISIBLE) {
-      if (mFrameRateControl != null) {
-        mFrameRateControl.start();
-      }
-    }
-  }
-
-  @Override
-  public void OnVSync() {
-    if (mSDKInstance != null && mSDKInstance.get() != null) {
-      mSDKInstance.get().OnVSync();
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/Script.java b/android/sdk/src/main/java/com/taobao/weex/Script.java
deleted file mode 100644
index e18bb76..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/Script.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.text.TextUtils;
-
-public class Script {
-    private String mContent;
-    private byte[] mBinary;
-
-    public Script(String content) {
-        mContent = content;
-    }
-
-    public Script(byte[] binary) {
-        mBinary = binary;
-    }
-
-    public String getContent() {
-        return mContent;
-    }
-
-    public byte[] getBinary() {
-        return mBinary;
-    }
-
-    public int length() {
-        if (mContent != null) {
-            return mContent.length();
-        } else if (mBinary != null){
-            return mBinary.length;
-        }
-        return 0;
-    }
-
-    public boolean isEmpty() {
-        return TextUtils.isEmpty(mContent) && (mBinary == null || mBinary.length == 0);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java b/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
deleted file mode 100644
index 0df6105..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import static android.content.Context.MODE_PRIVATE;
-
-import android.annotation.SuppressLint;
-import android.app.Application;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Typeface;
-import android.os.Environment;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import com.taobao.weex.common.WXConfig;
-import com.taobao.weex.utils.FontDO;
-import com.taobao.weex.utils.LogLevel;
-import com.taobao.weex.utils.TypefaceUtil;
-import com.taobao.weex.utils.WXFileUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXSoInstallMgrSdk;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import dalvik.system.PathClassLoader;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-public class WXEnvironment {
-
-  public static final String OS = "android";
-  public static String SYS_VERSION = android.os.Build.VERSION.RELEASE;
-  static{
-    if(SYS_VERSION != null && SYS_VERSION.toUpperCase(Locale.ROOT).equals("P")){
-        SYS_VERSION = "9.0.0";
-    }
-    if(SYS_VERSION != null && SYS_VERSION.toUpperCase(Locale.ROOT).equals("Q")){
-       SYS_VERSION = "10.0.0";
-    }
-  }
-  public static final String SYS_MODEL = android.os.Build.MODEL;
-  public static final String EAGLE = "eagle";
-  public static final String ENVIRONMENT = "environment";
-  public static final String WEEX_CURRENT_KEY = "wx_current_url";
-  /*********************
-   * Global config
-   ***************************/
-
-  public static String JS_LIB_SDK_VERSION = BuildConfig.buildJavascriptFrameworkVersion;
-
-  public static String WXSDK_VERSION = BuildConfig.buildVersion;
-  public static Application sApplication;
-  public static final String DEV_Id = getDevId();
-  @Deprecated
-  public static int sDefaultWidth = 750;
-  public volatile static boolean JsFrameworkInit = false;
-
-  public static final String SETTING_EXCLUDE_X86SUPPORT = "env_exclude_x86";
-
-  public static boolean SETTING_FORCE_VERTICAL_SCREEN = false;
-
-  /**
-   * auto adjust device width for when screen size change.
-   * */
-  public static boolean AUTO_ADJUST_ENV_DEVICE_WIDTH = true;
-
-  public static boolean AUTO_UPDATE_APPLICATION_SCREEN_SIZE = true;
-
-  public static volatile boolean sUseRunTimeApi = false;
-
-  /**
-   * Debug model
-   */
-  public static boolean sDebugMode = false;
-  public static final boolean sForceEnableDevTool = true;
-  public static String sDebugWsUrl = "";
-  public static boolean sDebugServerConnectable = false;
-  public static boolean sRemoteDebugMode = false;
-  public static String sRemoteDebugProxyUrl = "";
-  public static boolean sDebugNetworkEventReporterEnable = false;//debugtool network switch
-  public static long sJSLibInitTime = 0;
-
-  public static long sSDKInitStart = 0;// init start timestamp
-  public static long sSDKInitInvokeTime = 0;//time cost to invoke init method
-  public static long sSDKInitExecuteTime = 0;//time cost to execute init job
-  /** from init to sdk-ready **/
-  public static long sSDKInitTime =0;
-
-  public static long sJSFMStartListenerTime=0;
-
-  public static volatile boolean isWsFixMode = true;
-
-  /**
-   * component and modules ready
-   * */
-  public static long sComponentsAndModulesReadyTime = 0;
-
-  public static boolean sInAliWeex = false;
-
-  public static LogLevel sLogLevel = LogLevel.DEBUG;
-  private static boolean isApkDebug = true;
-  public static boolean isPerf = false;
-  private static boolean sDebugFlagInit = false;
-
-  private static boolean openDebugLog = true;
-
-  private static String sGlobalFontFamily;
-
-  public static final String CORE_SO_NAME = "weexcore";
-  public static final String CORE_JSS_SO_NAME = "weexjss";
-  public static final String CORE_JSB_SO_NAME = "weexjsb";
-  public static final String CORE_JST_SO_NAME = "weexjst";
-  public static final String CORE_JSC_SO_NAME = "JavaScriptCore";
-  private static  String CORE_JSS_SO_PATH = null;
-
-  public static  String CORE_JSS_RUNTIME_SO_PATH = null;
-
-  private static String CORE_JSS_ICU_PATH = null;
-
-  private static String CORE_JSC_SO_PATH = null;
-
-  public static String CORE_JSB_SO_PATH = null;
-
-  private static String COPY_SO_DES_DIR = null;
-
-  private static String LIB_LD_PATH = null;
-
-  private static Map<String, String> options = new ConcurrentHashMap<>();
-  static {
-    options.put(WXConfig.os, OS);
-    options.put(WXConfig.osName, OS);
-  }
-
-
-  public static synchronized WXDefaultSettings getWXDefaultSettings() {
-    if (mWXDefaultSettings == null && getApplication() != null) {
-      mWXDefaultSettings = new WXDefaultSettings(getApplication());
-    }
-    return mWXDefaultSettings;
-  }
-
-  public static synchronized String getDefaultSettingValue(String key, String defaultValue) {
-    WXDefaultSettings wxDefaultSettings = getWXDefaultSettings();
-    if (wxDefaultSettings == null || TextUtils.isEmpty(key)) {
-      return defaultValue;
-    }
-    return wxDefaultSettings.getValue(key, defaultValue);
-  }
-
-  public static synchronized void writeDefaultSettingsValue(String key, String value) {
-    WXDefaultSettings wxDefaultSettings = getWXDefaultSettings();
-    if (wxDefaultSettings == null
-            || TextUtils.isEmpty(key)
-            || TextUtils.isEmpty(value)) {
-      return;
-    }
-    wxDefaultSettings.saveValue(key, value);
-  }
-
-  private static WXDefaultSettings mWXDefaultSettings;
-
-  /**
-   * dynamic
-   */
-  public static boolean sDynamicMode = false;
-  public static String sDynamicUrl = "";
-
-  /**
-   * Fetch system information.
-   * @return map contains system information.
-   */
-  public static Map<String, String> getConfig() {
-    Map<String, String> configs = new HashMap<>();
-    configs.put(WXConfig.os, OS);
-    configs.put(WXConfig.appVersion, getAppVersionName());
-    configs.put(WXConfig.cacheDir, getAppCacheFile());
-    configs.put(WXConfig.devId, DEV_Id);
-    configs.put(WXConfig.sysVersion, SYS_VERSION);
-    configs.put(WXConfig.sysModel, SYS_MODEL);
-    configs.put(WXConfig.weexVersion, String.valueOf(WXSDK_VERSION));
-
-    try {
-      configs.put(WXConfig.layoutDirection, isLayoutDirectionRTL() ? "rtl" : "ltr");
-    } catch (Exception e) {
-      configs.put(WXConfig.layoutDirection, "ltr");
-    }
-
-    try {
-      if (isApkDebugable()) {
-        addCustomOptions(WXConfig.debugMode, "true");
-      }
-      addCustomOptions(WXConfig.scale, Float.toString(sApplication.getResources().getDisplayMetrics().density));
-      addCustomOptions(WXConfig.androidStatusBarHeight, Float.toString(WXViewUtils.getStatusBarHeight(sApplication)));
-    }catch (NullPointerException e){
-      //There is little chance of NullPointerException as sApplication may be null.
-      WXLogUtils.e("WXEnvironment scale Exception: ", e);
-    }
-    configs.putAll(getCustomOptions());
-    if(configs.get(WXConfig.appName)==null && sApplication!=null){
-      configs.put(WXConfig.appName, sApplication.getPackageName());
-    }
-    return configs;
-  }
-
-  /**
-   * Get the version of the current app.
-   */
-  public static String getAppVersionName() {
-    String versionName = "";
-    PackageManager manager;
-    PackageInfo info = null;
-    try {
-      manager = sApplication.getPackageManager();
-      info = manager.getPackageInfo(sApplication.getPackageName(), 0);
-      versionName = info.versionName;
-    } catch (Exception e) {
-      WXLogUtils.e("WXEnvironment getAppVersionName Exception: ", e);
-    }
-    return versionName;
-  }
-
-  /**
-   *
-   * @return string cache file
-   */
-  private static String getAppCacheFile() {
-    String cache = "";
-    try {
-      cache = sApplication.getApplicationContext().getCacheDir().getPath();
-    } catch (Exception e) {
-      WXLogUtils.e("WXEnvironment getAppCacheFile Exception: ", e);
-    }
-    return cache;
-  }
-
-
-  /**
-   * Use {@link #addCustomOptions(String, String)} to add custom options.
-   * Use {@link #getCustomOptions(String)} to get custom options
-   * @return
-   */
-  @Deprecated
-  public static Map<String, String> getCustomOptions() {
-    return options;
-  }
-
-  public static void addCustomOptions(String key, String value) {
-    options.put(key, value);
-  }
-
-  public static String getCustomOptions(String key){
-    return options.get(key);
-  }
-
-
-  @SuppressLint("SdCardPath")
-  public static String copySoDesDir() {
-    try {
-      if (TextUtils.isEmpty(COPY_SO_DES_DIR)) {
-        if (sApplication == null) {
-          WXLogUtils.e("sApplication is null, so copy path will be null");
-          return null;
-        }
-
-        String dirName = "/cache/weex/libs";
-        File desDir = null;
-        String cachePath = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
-
-        if (TextUtils.isEmpty(cachePath)) {
-          desDir = new File(cachePath, dirName);
-        } else {
-          String pkgName = sApplication.getPackageName();
-          String toPath = "/data/data/" + pkgName + dirName;
-          desDir = new File(toPath);
-        }
-
-        if (!desDir.exists()) {
-          desDir.mkdirs();
-        }
-        COPY_SO_DES_DIR = desDir.getAbsolutePath();
-      }
-    } catch (Throwable e) {
-      WXLogUtils.e(WXLogUtils.getStackTrace(e));
-    }
-    return COPY_SO_DES_DIR;
-
-  }
-
-  @Deprecated
-  /**
-   * Use {@link #isHardwareSupport()} if you want to see whether current hardware support Weex.
-   */
-  public static boolean isSupport() {
-    boolean isInitialized = WXSDKEngine.isInitialized();
-    if(!isInitialized){
-      WXLogUtils.e("WXSDKEngine.isInitialized():" + isInitialized);
-    }
-    return isHardwareSupport() && isInitialized;
-  }
-
-  public static boolean isLayoutDirectionRTL() {
-    // support RTL
-    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-      return sApplication.getApplicationContext().getResources().getBoolean(R.bool.weex_is_right_to_left);
-    }
-    return false;
-  }
-  /**
-   * Tell whether Weex can run on current hardware.
-   * @return true if weex can run on current hardware, otherwise false.
-   * Weex has removed the restrictions on the tablet, please use {@link #isCPUSupport()}
-   */
-  @Deprecated
-  public static boolean isHardwareSupport() {
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("isTableDevice:" + WXUtils.isTabletDevice());
-    }
-    return isCPUSupport();
-  }
-
-  /**
-   * Determine whether Weex supports the current CPU architecture
-   * @return true when support
-   */
-  public static boolean isCPUSupport(){
-    boolean excludeX86 = "true".equals(getCustomOptions().get(SETTING_EXCLUDE_X86SUPPORT));
-    boolean isX86AndExcluded = WXSoInstallMgrSdk.isX86() && excludeX86;
-    boolean isCPUSupport = WXSoInstallMgrSdk.isCPUSupport() && !isX86AndExcluded;
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("WXEnvironment.sSupport:" + isCPUSupport
-              + "isX86AndExclueded: "+ isX86AndExcluded);
-    }
-    return isCPUSupport;
-  }
-
-  public static boolean isApkDebugable() {
-    return isApkDebugable(sApplication);
-  }
-
-  public static boolean isApkDebugable(Application application) {
-    if (application == null) {
-      return false;
-    }
-
-    if (isPerf) {
-      return false;
-    }
-
-    if (sDebugFlagInit){
-      return isApkDebug;
-    }
-    try {
-      String debugModeConfig = getCustomOptions().get(WXConfig.debugMode);
-      if (TextUtils.isEmpty(debugModeConfig)){
-        ApplicationInfo info = application.getApplicationInfo();
-        isApkDebug = (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-      }else {
-        isApkDebug = Boolean.valueOf(debugModeConfig);
-      }
-    } catch (Exception e) {
-      /**
-       * Don't call WXLogUtils.e here,will cause stackoverflow
-       */
-      e.printStackTrace();
-      isApkDebug = false;
-    }
-    sDebugFlagInit = true;
-    return isApkDebug;
-  }
-
-  public static boolean isPerf() {
-    return isPerf;
-  }
-
-  @SuppressLint("HardwareIds")
-  private static String getDevId() {
-    String ret = "";
-    if(sApplication != null){
-      try{
-        ret = ((TelephonyManager) sApplication
-            .getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
-      }catch (SecurityException | NullPointerException e){
-        WXLogUtils.e(WXLogUtils.getStackTrace(e));
-      }
-    }
-    return ret;
-  }
-
-  public static Application getApplication() {
-    return sApplication;
-  }
-
-  public void initMetrics() {
-    if (sApplication == null) {
-      return;
-    }
-  }
-
-  public static String getDiskCacheDir(Context context) {
-    if (context == null) {
-      return null;
-    }
-    String cachePath = null;
-    try {
-      if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
-              || !Environment.isExternalStorageRemovable()) {
-        cachePath = context.getExternalCacheDir().getPath();
-      } else {
-        cachePath = context.getCacheDir().getPath();
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-    return cachePath;
-  }
-
-  public static String getFilesDir(Context context) {
-    if (context == null) {
-      return "";
-    }
-    File filesDir = context.getFilesDir();
-    String path = "";
-    if (filesDir != null) {
-      path = filesDir.getPath();
-    } else {
-      path = WXEnvironment.getApplication().getApplicationInfo().dataDir;
-      path += File.separator;
-      path += "files";
-    }
-
-    return path;
-  }
-
-  public static String getCrashFilePath(Context context) {
-    if (context == null) {
-        return "";
-    }
-
-    File dir = context.getDir("crash", Context.MODE_PRIVATE);
-    if (dir == null)
-        return "";
-
-    String crashDir = dir.getAbsolutePath();
-
-    return crashDir;
-  }
-
-  public static String getGlobalFontFamilyName() {
-    return sGlobalFontFamily;
-  }
-
-  public static void setGlobalFontFamily(String fontFamilyName, Typeface typeface) {
-    WXLogUtils.d("GlobalFontFamily", "Set global font family: " + fontFamilyName);
-    sGlobalFontFamily = fontFamilyName;
-    if (!TextUtils.isEmpty(fontFamilyName)) {
-      if (typeface == null) {
-        TypefaceUtil.removeFontDO(fontFamilyName);
-      } else {
-        FontDO nativeFontDO = new FontDO(fontFamilyName, typeface);
-        TypefaceUtil.putFontDO(nativeFontDO);
-        WXLogUtils.d("TypefaceUtil", "Add new font: " + fontFamilyName);
-      }
-    }
-  }
-
-  public static boolean isOpenDebugLog() {
-    return openDebugLog;
-  }
-
-  public static void setOpenDebugLog(boolean openDebugLog) {
-    WXEnvironment.openDebugLog = openDebugLog;
-  }
-
-  public static void  setApkDebugable(boolean debugable){
-    isApkDebug  = debugable;
-    if(!isApkDebug){
-      openDebugLog = false;
-    }
-  }
-
-  public static String getCacheDir() {
-    final Application application = getApplication();
-    if (application == null || application.getApplicationContext() == null)
-      return null;
-    return application.getApplicationContext().getCacheDir().getPath();
-  }
-
-  public static boolean extractSo() {
-    File sourceFile = new File(getApplication().getApplicationContext().getApplicationInfo().sourceDir);
-    final String soDesPath = copySoDesDir();
-    if (sourceFile.exists() && !TextUtils.isEmpty(soDesPath)) {
-      try {
-        WXFileUtils.extractSo(sourceFile.getAbsolutePath(), soDesPath);
-      } catch (IOException e) {
-        WXLogUtils.e("extractSo error " + e.getMessage());
-//        e.printStackTrace();
-        return false;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  private static String findIcuPath() {
-    File file = new File("/proc/self/maps");
-    BufferedReader reader = null;
-    try {
-      reader = new BufferedReader(new FileReader(file));
-      String tempString = null;
-      while ((tempString = reader.readLine()) != null) {
-        if (tempString.contains("icudt")) {
-
-          int i = tempString.indexOf('/');
-
-          String substring = tempString.substring(i);
-          return substring.trim();
-        }
-      }
-      reader.close();
-    } catch (IOException e) {
-      e.printStackTrace();
-    } finally {
-      if (reader != null) {
-        try {
-          reader.close();
-        } catch (IOException e1) {
-        }
-      }
-    }
-
-    return null;
-  }
-
-
-  public static String findSoPath(String libName) {
-    String soPath = ((PathClassLoader) (WXEnvironment.class.getClassLoader())).findLibrary(libName);
-    if (!TextUtils.isEmpty(soPath)) {
-      File soFile = new File(soPath);
-      if (soFile.exists()) {
-        WXLogUtils.e(libName + "'s Path is" + soPath);
-        return soFile.getAbsolutePath();
-      } else {
-        WXLogUtils.e(libName + "'s Path is " + soPath + " but file does not exist");
-      }
-    }
-
-    String realName = "lib" + libName + ".so";
-    String cacheDir = getCacheDir();
-    if (TextUtils.isEmpty(cacheDir)) {
-      WXLogUtils.e("cache dir is null");
-      return "";
-    }
-
-
-    if (cacheDir.indexOf("/cache") > 0) {
-      soPath = new File(cacheDir.replace("/cache", "/lib"), realName).getAbsolutePath();
-    }
-
-
-    final File soFile = new File(soPath);
-    if (soFile.exists()) {
-      WXLogUtils.e(libName + "use lib so");
-      return soPath;
-    } else {
-      //unzip from apk file
-      final boolean success = extractSo();
-      if (success) {
-        return new File(getCacheDir(), realName).getAbsolutePath();
-      }
-    }
-    return soPath;
-  }
-
-  public static String getLibJScRealPath() {
-    if(TextUtils.isEmpty(CORE_JSC_SO_PATH)) {
-      CORE_JSC_SO_PATH = findSoPath(CORE_JSC_SO_NAME);
-      WXLogUtils.e("findLibJscRealPath " + CORE_JSC_SO_PATH);
-    }
-    return CORE_JSC_SO_PATH;
-  }
-
-  public static String getLibJssRealPath() {
-    if (WXEnvironment.sUseRunTimeApi && !TextUtils.isEmpty(CORE_JSS_RUNTIME_SO_PATH)){
-      WXLogUtils.d("test-> findLibJssRuntimeRealPath " + CORE_JSS_RUNTIME_SO_PATH);
-      return CORE_JSS_RUNTIME_SO_PATH;
-    }
-
-    if(TextUtils.isEmpty(CORE_JSS_SO_PATH)) {
-      CORE_JSS_SO_PATH = findSoPath(CORE_JSS_SO_NAME);
-      WXLogUtils.d("test-> findLibJssRealPath " + CORE_JSS_SO_PATH);
-    }
-
-    return CORE_JSS_SO_PATH;
-  }
-
-  public static String getLibJssIcuPath() {
-    if(TextUtils.isEmpty(CORE_JSS_ICU_PATH)){
-      CORE_JSS_ICU_PATH = findIcuPath();
-    }
-
-    return CORE_JSS_ICU_PATH;
-  }
-
-  public static String getLibLdPath() {
-    if (TextUtils.isEmpty(LIB_LD_PATH)) {
-      ClassLoader classLoader = WXEnvironment.class.getClassLoader();
-      try {
-        Method getLdLibraryPath = classLoader.getClass().getMethod("getLdLibraryPath", new Class[0]);
-        LIB_LD_PATH = (String) getLdLibraryPath.invoke(classLoader, new Object[0]);
-      } catch (IllegalAccessException e) {
-        e.printStackTrace();
-      } catch (InvocationTargetException e) {
-        e.printStackTrace();
-      } catch (NoSuchMethodException e) {
-        e.printStackTrace();
-      }
-    }
-
-    if(TextUtils.isEmpty(LIB_LD_PATH)) {
-      try {
-        String property = System.getProperty("java.library.path");
-        String libJScRealPath = getLibJScRealPath();
-        if(!TextUtils.isEmpty(libJScRealPath)) {
-          LIB_LD_PATH = new File(libJScRealPath).getParent() + ":" + property;
-        }
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-    }
-
-    WXLogUtils.d("getLibLdPath is " + LIB_LD_PATH);
-    return LIB_LD_PATH;
-  }
-
-  public static class WXDefaultSettings {
-    private String configName = "weex_default_settings";
-    private SharedPreferences sharedPreferences = null;
-    public WXDefaultSettings(Application application) {
-      if(application != null) {
-        sharedPreferences = application.getSharedPreferences(configName, MODE_PRIVATE);
-      }
-    }
-
-    public synchronized String getValue(String key, String defaultValue) {
-      if(sharedPreferences == null || TextUtils.isEmpty(key)) {
-        WXLogUtils.i("get default settings " + key + " return default value :" + defaultValue);
-        return defaultValue;
-      }
-
-      String result = sharedPreferences.getString(key, defaultValue);
-      WXLogUtils.i("get default settings " + key + " : " + result);
-      return result;
-    }
-
-    public synchronized void saveValue(String key, String value) {
-      if (sharedPreferences == null
-              || TextUtils.isEmpty(key)
-              || TextUtils.isEmpty(value)) {
-        return;
-      }
-      WXLogUtils.i("save default settings " + key + ":" + value);
-      SharedPreferences.Editor editor = sharedPreferences.edit();
-      editor.putString(key, value);
-      editor.apply();
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXGlobalEventModule.java b/android/sdk/src/main/java/com/taobao/weex/WXGlobalEventModule.java
deleted file mode 100644
index b487ba2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WXGlobalEventModule.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.WXModule;
-
-import java.util.Map;
-
-/**
- * Created by lixinke on 16/8/25.
- */
-public class WXGlobalEventModule extends WXModule {
-
-
-  @JSMethod
-  public void addEventListener(String eventName, String callback) {
-    mWXSDKInstance.addEventListener(eventName,callback);
-  }
-
-  public void removeEventListener(String eventName, String callback) {
-    mWXSDKInstance.removeEventListener(eventName,callback);
-  }
-
-  @JSMethod
-  public void removeEventListener(String eventName){
-    mWXSDKInstance.removeEventListener(eventName);
-  }
-
-
-  @Override
-  public void addEventListener(String eventName, String callback, Map<String, Object> options) {
-    super.addEventListener(eventName, callback, options);
-    addEventListener(eventName,callback);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXGlobalEventReceiver.java b/android/sdk/src/main/java/com/taobao/weex/WXGlobalEventReceiver.java
deleted file mode 100644
index 82e8363..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WXGlobalEventReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.HashMap;
-
-public class WXGlobalEventReceiver extends BroadcastReceiver {
-
-  public static final String EVENT_NAME = "eventName";
-  public static final String EVENT_PARAMS = "eventParams";
-  public static final String EVENT_ACTION = "wx_global_action";
-  public static final String EVENT_WX_INSTANCEID = "wx_instanceid";
-
-  private WXSDKInstance mWXSDKInstance;
-
-  public WXGlobalEventReceiver() {
-  }
-
-  public WXGlobalEventReceiver(WXSDKInstance instance) {
-    mWXSDKInstance = instance;
-  }
-
-  @Override
-  public void onReceive(Context context, Intent intent) {
-    String eventName = intent.getStringExtra(EVENT_NAME);
-    String params = intent.getStringExtra(EVENT_PARAMS);
-    HashMap<String, Object> maps = null;
-    try {
-      maps = com.alibaba.fastjson.JSON.parseObject(params, HashMap.class);
-      mWXSDKInstance.fireGlobalEventCallback(eventName, maps);
-    } catch (Exception e) {
-      WXLogUtils.e("global-receive",e);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXHttpListener.java b/android/sdk/src/main/java/com/taobao/weex/WXHttpListener.java
deleted file mode 100644
index 15d9cf2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WXHttpListener.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.net.Uri;
-import android.text.TextUtils;
-
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXPerformance;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.common.WXResponse;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.tracing.WXTracing;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.tools.LogDetail;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * load bundle js listener
- */
-public class WXHttpListener implements IWXHttpAdapter.OnHttpListener {
-
-    private String pageName;
-    private Map<String, Object> options;
-    private String jsonInitData;
-    private WXRenderStrategy flag;
-    private WXSDKInstance instance;
-    private long startRequestTime;
-    private int traceId;
-    private WXPerformance mWXPerformance;
-    private WXInstanceApm mApmForInstance;
-    private IWXUserTrackAdapter mUserTrackAdapter;
-    public boolean isPreDownLoadMode = false;
-    private boolean isInstanceReady =false;
-    private boolean isResponseHasWait = false;
-    private WXResponse mResponse;
-    private LogDetail mLogDetail;
-
-    private String mBundleUrl;
-
-    public WXHttpListener(WXSDKInstance instance) {
-        if(instance != null) {
-            mLogDetail = instance.mTimeCalculator.createLogDetail("downloadBundleJS");
-        }
-        this.instance = instance;
-        this.traceId = WXTracing.nextId();
-        this.mWXPerformance = instance.getWXPerformance();
-        this.mApmForInstance = instance.getApmForInstance();
-        this.mUserTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
-        if (WXTracing.isAvailable()) {
-            WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
-            event.iid = instance.getInstanceId();
-            event.tname = "Network";
-            event.ph = "B";
-            event.traceId = traceId;
-            event.submit();
-        }
-    }
-
-    public WXHttpListener(WXSDKInstance instance, String bundleUrl) {
-        this(instance);
-        this.startRequestTime = System.currentTimeMillis();
-        this.mBundleUrl = bundleUrl;
-    }
-
-    public WXHttpListener(WXSDKInstance instance, String pageName, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag, long startRequestTime) {
-        this(instance);
-        this.pageName = pageName;
-        this.options = options;
-        this.jsonInitData = jsonInitData;
-        this.flag = flag;
-        this.startRequestTime = startRequestTime;
-        this.mBundleUrl = instance.getBundleUrl();
-    }
-
-    public void setSDKInstance(WXSDKInstance instance) {
-        this.instance = instance;
-    }
-
-    protected WXSDKInstance getInstance() {
-        return instance;
-    }
-
-    @Override
-    public void onHttpStart() {
-        if (this.instance != null
-                && this.instance.getWXStatisticsListener() != null) {
-            this.instance.getWXStatisticsListener().onHttpStart();
-            if(mLogDetail != null) {
-                mLogDetail.taskStart();
-            }
-        }
-    }
-
-    @Override
-    public void onHeadersReceived(int statusCode, Map<String,List<String>> headers) {
-        if (this.instance != null
-                && this.instance.getWXStatisticsListener() != null) {
-            this.instance.getWXStatisticsListener().onHeadersReceived();
-            this.instance.onHttpStart();
-        }
-        if(this.instance != null
-                && this.instance.responseHeaders != null
-                && headers != null){
-            this.instance.responseHeaders.putAll(headers);
-        }
-    }
-
-    @Override
-    public void onHttpUploadProgress(int uploadProgress) {
-
-    }
-
-    @Override
-    public void onHttpResponseProgress(int loadedLength) {
-        instance.getApmForInstance().extInfo.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadedLength);
-    }
-
-    @Override
-    public void onHttpFinish(WXResponse response) {
-        if(mLogDetail != null) {
-            mLogDetail.taskEnd();
-        }
-        if (this.instance != null
-                && this.instance.getWXStatisticsListener() != null) {
-            this.instance.getWXStatisticsListener().onHttpFinish();
-        }
-
-        if (WXTracing.isAvailable()) {
-            WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
-            event.traceId = traceId;
-            event.tname = "Network";
-            event.ph = "E";
-            event.extParams = new HashMap<>();
-            if (response != null && response.originalData != null) {
-                event.extParams.put("BundleSize", response.originalData.length);
-            }
-            event.submit();
-        }
-
-        mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime;
-        if(null!= response && response.extendParams!=null){
-            mApmForInstance.updateRecordInfo(response.extendParams);
-            Object actualNetworkTime=response.extendParams.get("actualNetworkTime");
-            mWXPerformance.actualNetworkTime=actualNetworkTime instanceof Long?(long)actualNetworkTime:0;
-
-            Object pureNetworkTime=response.extendParams.get("pureNetworkTime");
-            mWXPerformance.pureNetworkTime=pureNetworkTime instanceof Long?(long)pureNetworkTime:0;
-
-            Object connectionType=response.extendParams.get("connectionType");
-            mWXPerformance.connectionType=connectionType instanceof String?(String)connectionType:"";
-
-            Object packageSpendTime=response.extendParams.get("packageSpendTime");
-            mWXPerformance.packageSpendTime=packageSpendTime instanceof Long ?(long)packageSpendTime:0;
-
-            Object syncTaskTime=response.extendParams.get("syncTaskTime");
-            mWXPerformance.syncTaskTime=syncTaskTime instanceof Long ?(long)syncTaskTime:0;
-
-            Object requestType=response.extendParams.get("requestType");
-            mWXPerformance.requestType=requestType instanceof String?(String)requestType:"none";
-
-            Object cacheType = response.extendParams.get(WXPerformance.Dimension.cacheType.toString());
-            if(cacheType instanceof String){
-                mWXPerformance.cacheType = (String) cacheType;
-            }
-
-            Object zCacheInfo = response.extendParams.get("zCacheInfo");
-            mWXPerformance.zCacheInfo = zCacheInfo instanceof String?(String)zCacheInfo:"";
-
-            if(isNet(mWXPerformance.requestType) && mUserTrackAdapter!=null){
-                WXPerformance performance=new WXPerformance(instance.getInstanceId());
-                if(!TextUtils.isEmpty(mBundleUrl)){
-                    try {
-                        performance.args= Uri.parse(mBundleUrl).buildUpon().clearQuery().toString();
-                    } catch (Exception e) {
-                        performance.args=pageName;
-                    }
-                }
-                if(!"200".equals(response.statusCode)){
-                    performance.errCode= WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
-                    performance.appendErrMsg(response.errorCode);
-                    performance.appendErrMsg("|");
-                    performance.appendErrMsg(response.errorMsg);
-
-                }else if("200".equals(response.statusCode) && (response.originalData==null || response.originalData.length<=0)){
-                    performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
-                    performance.appendErrMsg(response.statusCode);
-                    performance.appendErrMsg("|template is null!");
-                }else {
-                    performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode();
-                }
-
-                if (mUserTrackAdapter != null) {
-                    mUserTrackAdapter.commit(instance.getContext(), null, IWXUserTrackAdapter.JS_DOWNLOAD, performance, null);
-                }
-            }
-        }
-
-        if (isPreDownLoadMode){
-            if (isInstanceReady){
-                WXLogUtils.d("test->", "DownLoad didHttpFinish on http" );
-                didHttpFinish(response);
-            }else {
-                WXLogUtils.d("test->", "DownLoad end before activity created" );
-                mResponse = response;
-                isResponseHasWait = true;
-            }
-        }else {
-            didHttpFinish(response);
-        }
-
-    }
-
-    public void onInstanceReady(){
-        if (!isPreDownLoadMode){
-            return;
-        }
-        this.isInstanceReady = true;
-        if (isResponseHasWait){
-            WXLogUtils.d("test->", "preDownLoad didHttpFinish on ready" );
-            this.didHttpFinish(mResponse);
-        }
-
-    }
-
-    private void didHttpFinish(WXResponse response){
-        String wxErrorCode = WXInstanceApm.VALUE_ERROR_CODE_DEFAULT;
-        if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) {
-            mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END);
-            onSuccess(response);
-
-            // check content-type
-        } else if (TextUtils.equals(WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode(),
-                response.statusCode)) {
-            WXLogUtils.e("user intercept: WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR");
-            wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode();
-            instance.onRenderError(wxErrorCode,
-                    "|response.errorMsg==" + response.errorMsg +
-                            "|instance bundleUrl = \n" + instance.getBundleUrl() +
-                            "|instance requestUrl = \n" + Uri.decode(WXSDKInstance.requestUrl)
-            );
-            onFail(response);
-
-            // check content-length
-        } else if (response!=null && response.originalData!=null && TextUtils.equals("-206", response.statusCode)) {
-            WXLogUtils.e("user intercept: WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED");
-            wxErrorCode =  WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode();
-            instance.onRenderError(wxErrorCode ,
-                    WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode() +
-                            "|response.errorMsg==" + response.errorMsg
-            );
-            onFail(response);
-        }
-        else {
-            wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode();
-            instance.onRenderError(wxErrorCode,
-                    response.errorMsg);
-            onFail(response);
-        }
-        if (!WXInstanceApm.VALUE_ERROR_CODE_DEFAULT.equals(wxErrorCode)){
-            mApmForInstance.addProperty(WXInstanceApm.KEY_PROPERTIES_ERROR_CODE,wxErrorCode);
-        }
-    }
-
-    private boolean isNet(String requestType){
-
-        return "network".equals(requestType) || "2g".equals(requestType) || "3g".equals(requestType)
-                || "4g".equals(requestType) || "wifi".equals(requestType) || "other".equals(requestType)
-                || "unknown".equals(requestType);
-    }
-
-    public void onSuccess(WXResponse response) {
-        if (flag==WXRenderStrategy.DATA_RENDER_BINARY){
-            instance.render(pageName, response.originalData, options, jsonInitData);
-        }else {
-            String template = new String(response.originalData);
-            instance.render(pageName, template, options, jsonInitData, flag);
-        }
-    }
-
-    public void onFail(WXResponse response) {
-
-    }
-}
-
-
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKEngine.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKEngine.java
deleted file mode 100644
index d9ef522..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKEngine.java
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import static com.taobao.weex.WXEnvironment.CORE_SO_NAME;
-
-import android.app.Application;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.support.v4.content.LocalBroadcastManager;
-import android.text.TextUtils;
-import com.taobao.weex.adapter.IDrawableLoader;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.adapter.IWXImgLoaderAdapter;
-import com.taobao.weex.adapter.IWXJSExceptionAdapter;
-import com.taobao.weex.adapter.IWXJsFileLoaderAdapter;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.appfram.clipboard.WXClipboardModule;
-import com.taobao.weex.appfram.navigator.IActivityNavBarSetter;
-import com.taobao.weex.appfram.navigator.INavigator;
-import com.taobao.weex.appfram.navigator.WXNavigatorModule;
-import com.taobao.weex.appfram.pickers.WXPickersModule;
-import com.taobao.weex.appfram.storage.IWXStorageAdapter;
-import com.taobao.weex.appfram.storage.WXStorageModule;
-import com.taobao.weex.appfram.websocket.WebSocketModule;
-import com.taobao.weex.bridge.ModuleFactory;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.bridge.WXModuleManager;
-import com.taobao.weex.bridge.WXServiceManager;
-import com.taobao.weex.common.Destroyable;
-import com.taobao.weex.common.TypeModuleFactory;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXException;
-import com.taobao.weex.common.WXInstanceWrap;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.http.WXStreamModule;
-import com.taobao.weex.performance.WXStateRecord;
-import com.taobao.weex.ui.ExternalLoaderComponentHolder;
-import com.taobao.weex.ui.IExternalComponentGetter;
-import com.taobao.weex.ui.IExternalModuleGetter;
-import com.taobao.weex.ui.IFComponentHolder;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import com.taobao.weex.ui.WXComponentRegistry;
-import com.taobao.weex.ui.animation.WXAnimationModule;
-import com.taobao.weex.ui.component.Textarea;
-import com.taobao.weex.ui.component.WXA;
-import com.taobao.weex.ui.component.WXBasicComponentType;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXDiv;
-import com.taobao.weex.ui.component.WXEmbed;
-import com.taobao.weex.ui.component.WXHeader;
-import com.taobao.weex.ui.component.WXImage;
-import com.taobao.weex.ui.component.WXIndicator;
-import com.taobao.weex.ui.component.WXInput;
-import com.taobao.weex.ui.component.WXLoading;
-import com.taobao.weex.ui.component.WXLoadingIndicator;
-import com.taobao.weex.ui.component.WXRefresh;
-import com.taobao.weex.ui.component.WXScroller;
-import com.taobao.weex.ui.component.WXSlider;
-import com.taobao.weex.ui.component.WXSliderNeighbor;
-import com.taobao.weex.ui.component.WXSwitch;
-import com.taobao.weex.ui.component.WXText;
-import com.taobao.weex.ui.component.WXVideo;
-import com.taobao.weex.ui.component.WXWeb;
-import com.taobao.weex.ui.component.list.HorizontalListComponent;
-import com.taobao.weex.ui.component.list.SimpleListComponent;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.component.list.WXListComponent;
-import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
-import com.taobao.weex.ui.component.richtext.WXRichText;
-import com.taobao.weex.ui.config.AutoScanConfigRegister;
-import com.taobao.weex.ui.module.WXDeviceInfoModule;
-import com.taobao.weex.ui.module.ConsoleLogModule;
-import com.taobao.weex.ui.module.WXLocaleModule;
-import com.taobao.weex.ui.module.WXMetaModule;
-import com.taobao.weex.ui.module.WXModalUIModule;
-import com.taobao.weex.ui.module.WXTimerModule;
-import com.taobao.weex.ui.module.WXWebViewModule;
-import com.taobao.weex.utils.LogLevel;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXSoInstallMgrSdk;
-import com.taobao.weex.utils.batch.BatchOperationHelper;
-import com.taobao.weex.utils.cache.RegisterCache;
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-
-public class WXSDKEngine implements Serializable {
-
-  public static final String JS_FRAMEWORK_RELOAD="js_framework_reload";
-  private static final String V8_SO_NAME = CORE_SO_NAME;
-  private volatile static boolean mIsInit = false;
-  private volatile static boolean mIsSoInit = false;
-  private static final Object mLock = new Object();
-  private static final String TAG = "WXSDKEngine";
-
-  /**
-   * Deprecated. Use {@link #initialize(Application, InitConfig)} instead.
-   */
-  @Deprecated
-  public static void init(Application application) {
-    init(application, null);
-  }
-
-  /**
-   * Deprecated. Use {@link #initialize(Application, InitConfig)} instead.
-   */
-  @Deprecated
-  public static void init(Application application, IWXUserTrackAdapter utAdapter) {
-    init(application, utAdapter, null);
-  }
-
-  /**
-   * Deprecated. Use {@link #initialize(Application, InitConfig)} instead.
-   */
-  @Deprecated
-  public static void init(Application application, IWXUserTrackAdapter utAdapter, String framework) {
-    initialize(application,
-            new InitConfig.Builder()
-                    .setUtAdapter(utAdapter)
-                    .build()
-    );
-  }
-
-
-  public static boolean isInitialized(){
-    synchronized(mLock) {
-
-      return mIsInit && WXEnvironment.JsFrameworkInit;
-    }
-  }
-
-  public static boolean isSoInitialized(){
-    synchronized(mLock) {
-      return mIsSoInit;
-    }
-  }
-
-  /**
-   *
-   * @param application
-   * @param config initial configurations or null
-   */
-  public static void initialize(Application application,InitConfig config){
-    synchronized (mLock) {
-      if (mIsInit) {
-        return;
-      }
-      long start = System.currentTimeMillis();
-      WXEnvironment.sSDKInitStart = start;
-      if(WXEnvironment.isApkDebugable(application)){
-        WXEnvironment.sLogLevel = LogLevel.DEBUG;
-      }else{
-        WXEnvironment.sLogLevel = LogLevel.WARN;
-      }
-      doInitInternal(application,config);
-      registerApplicationOptions(application);
-      WXEnvironment.sSDKInitInvokeTime = System.currentTimeMillis()-start;
-      WXLogUtils.renderPerformanceLog("SDKInitInvokeTime", WXEnvironment.sSDKInitInvokeTime);
-      mIsInit = true;
-    }
-  }
-
-  private static void registerApplicationOptions(final Application application) {
-
-    if (application == null) {
-      WXLogUtils.e(TAG, "RegisterApplicationOptions application is null");
-      return;
-    }
-
-    Resources resources = application.getResources();
-    registerCoreEnv("screen_width_pixels", String.valueOf(resources.getDisplayMetrics().widthPixels));
-    registerCoreEnv("screen_height_pixels", String.valueOf(resources.getDisplayMetrics().heightPixels));
-
-    int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
-    if (resourceId > 0) {
-      int statusBarHeight = resources.getDimensionPixelSize(resourceId);
-      registerCoreEnv("status_bar_height", String.valueOf(statusBarHeight));
-    }
-  }
-
-  private static void doInitInternal(final Application application,final InitConfig config){
-    WXEnvironment.sApplication = application;
-    if(application == null){
-      WXLogUtils.e(TAG, " doInitInternal application is null");
-      WXExceptionUtils.commitCriticalExceptionRT(null,
-              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
-              "doInitInternal",
-              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "WXEnvironment sApplication is null",
-              null);
-    }
-    WXEnvironment.JsFrameworkInit = false;
-
-    WXBridgeManager.getInstance().postWithName(new Runnable() {
-      @Override
-      public void run() {
-        long start = System.currentTimeMillis();
-        WXSDKManager sm = WXSDKManager.getInstance();
-        sm.onSDKEngineInitialize();
-        if(config != null ) {
-          sm.setInitConfig(config);
-        }
-        WXSoInstallMgrSdk.init(application,
-                sm.getIWXSoLoaderAdapter(),
-                sm.getWXStatisticsListener());
-        final IWXUserTrackAdapter userTrackAdapter= config!=null?config.getUtAdapter():null;
-        final int version = 1;
-        mIsSoInit = WXSoInstallMgrSdk.initSo(V8_SO_NAME, version, userTrackAdapter);
-        WXSoInstallMgrSdk.copyJssRuntimeSo();
-        if(config!=null) {
-          for (String libraryName : config.getNativeLibraryList()) {
-            WXSoInstallMgrSdk.initSo(libraryName, version, userTrackAdapter);
-          }
-        }
-        if (!mIsSoInit) {
-          WXExceptionUtils.commitCriticalExceptionRT(null,
-                  WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
-                  "doInitInternal",
-                  WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "isSoInit false",
-                  null);
-          return;
-        }
-        sm.initScriptsFramework(config!=null?config.getFramework():null);
-
-        WXEnvironment.sSDKInitExecuteTime = System.currentTimeMillis() - start;
-        WXLogUtils.renderPerformanceLog("SDKInitExecuteTime", WXEnvironment.sSDKInitExecuteTime);
-      }
-    },null,"doInitWeexSdkInternal");
-    WXStateRecord.getInstance().startJSThreadWatchDog();
-    register();
-  }
-
-  @Deprecated
-  public static void init(Application application, String framework, IWXUserTrackAdapter utAdapter, IWXImgLoaderAdapter imgLoaderAdapter, IWXHttpAdapter httpAdapter) {
-    initialize(application,
-            new InitConfig.Builder()
-                    .setUtAdapter(utAdapter)
-                    .setHttpAdapter(httpAdapter)
-                    .setImgAdapter(imgLoaderAdapter)
-                    .build()
-    );
-  }
-
-  public static void setJSExcetptionAdapter(IWXJSExceptionAdapter excetptionAdapter){
-    WXSDKManager.getInstance().setIWXJSExceptionAdapter(excetptionAdapter);
-  }
-
-  private static void register() {
-    BatchOperationHelper batchHelper = new BatchOperationHelper(WXBridgeManager.getInstance());
-    try {
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXText.class,
-                      new WXText.Creator()
-              ),
-              false,
-              WXBasicComponentType.TEXT
-      );
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXDiv.class,
-                      new WXDiv.Ceator()
-              ),
-              false,
-              WXBasicComponentType.CONTAINER,
-              WXBasicComponentType.DIV,
-              WXBasicComponentType.HEADER,
-              WXBasicComponentType.FOOTER
-      );
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXImage.class,
-                      new WXImage.Creator()
-              ),
-              false,
-              WXBasicComponentType.IMAGE,
-              WXBasicComponentType.IMG
-      );
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXScroller.class,
-                      new WXScroller.Creator()
-              ),
-              false,
-              WXBasicComponentType.SCROLLER
-      );
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXSlider.class,
-                      new WXSlider.Creator()
-              ),
-              true,
-              WXBasicComponentType.SLIDER,
-              WXBasicComponentType.CYCLE_SLIDER
-      );
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXSliderNeighbor.class,
-                      new WXSliderNeighbor.Creator()
-              ),
-              true,
-              WXBasicComponentType.SLIDER_NEIGHBOR
-      );
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXCell.class,
-                      new WXCell.Creator()
-              ),
-              true,
-              WXBasicComponentType.CELL);
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXListComponent.class,
-                      new WXListComponent.Creator()
-              ),
-              true,
-              WXBasicComponentType.LIST,
-              WXBasicComponentType.VLIST,
-              WXBasicComponentType.RECYCLER,
-              WXBasicComponentType.WATERFALL);
-
-      registerComponent(
-              new SimpleComponentHolder(
-                      WXRichText.class,
-                      new WXRichText.Creator()
-              ),
-              false,
-              WXBasicComponentType.RICHTEXT
-      );
-
-      String simpleList = "simplelist";
-      registerComponent(SimpleListComponent.class,false,simpleList);
-      registerComponent(WXRecyclerTemplateList.class, false,WXBasicComponentType.RECYCLE_LIST);
-      registerComponent(HorizontalListComponent.class,false,WXBasicComponentType.HLIST);
-      registerComponent(WXBasicComponentType.CELL_SLOT, WXCell.class, true);
-      registerComponent(WXBasicComponentType.INDICATOR, WXIndicator.class, true);
-      registerComponent(WXBasicComponentType.VIDEO, WXVideo.class, false);
-      registerComponent(WXBasicComponentType.INPUT, WXInput.class, false);
-      registerComponent(WXBasicComponentType.TEXTAREA, Textarea.class,false);
-      registerComponent(WXBasicComponentType.SWITCH, WXSwitch.class, false);
-      registerComponent(WXBasicComponentType.A, WXA.class, false);
-      registerComponent(WXBasicComponentType.EMBED, WXEmbed.class, true);
-      registerComponent(WXBasicComponentType.WEB, WXWeb.class);
-      registerComponent(WXBasicComponentType.REFRESH, WXRefresh.class);
-      registerComponent(WXBasicComponentType.LOADING, WXLoading.class);
-      registerComponent(WXBasicComponentType.LOADING_INDICATOR, WXLoadingIndicator.class);
-      registerComponent(WXBasicComponentType.HEADER, WXHeader.class);
-
-      registerModule("modal", WXModalUIModule.class);
-      registerModule("instanceWrap", WXInstanceWrap.class);
-      registerModule("animation", WXAnimationModule.class);
-      registerModule("webview", WXWebViewModule.class);
-      registerModule("navigator", WXNavigatorModule.class);
-      registerModule("stream", WXStreamModule.class);
-      registerModule("timer", WXTimerModule.class);
-      registerModule("storage", WXStorageModule.class);
-      registerModule("clipboard", WXClipboardModule.class);
-      registerModule("globalEvent",WXGlobalEventModule.class);
-      registerModule("picker", WXPickersModule.class);
-      registerModule("meta", WXMetaModule.class);
-      registerModule("webSocket", WebSocketModule.class);
-      registerModule("locale", WXLocaleModule.class);
-      registerModule("deviceInfo", WXDeviceInfoModule.class);
-      registerModule("sdk-console-log", ConsoleLogModule.class);
-    } catch (WXException e) {
-      WXLogUtils.e("[WXSDKEngine] register:", e);
-    }
-
-    if(RegisterCache.getInstance().enableAutoScan()) {
-      AutoScanConfigRegister.doScanConfig();
-    }
-
-    batchHelper.flush();
-  }
-
-  /**
-   *
-   * Register component. The registration is singleton in {@link WXSDKEngine} level
-   * @param type name of component. Same as type field in the JS.
-   * @param clazz the class of the {@link WXComponent} to be registered.
-   * @param appendTree true for appendTree flag
-   * @return true for registration success, false for otherwise.
-   * @throws WXException Throws exception if type conflicts.
-   */
-  public static boolean registerComponent(String type, Class<? extends WXComponent> clazz, boolean appendTree) throws WXException {
-    return registerComponent(clazz, appendTree,type);
-  }
-
-  public static boolean registerComponent(String type, IExternalComponentGetter componentGetter, boolean appendTree) throws WXException {
-    return registerComponent(new ExternalLoaderComponentHolder(type,componentGetter), appendTree,type);
-  }
-
-  /**
-   *
-   * Register component. The registration is singleton in {@link WXSDKEngine} level
-   * @param clazz the class of the {@link WXComponent} to be registered.
-   * @param appendTree true for appendTree flag
-   * @return true for registration success, false for otherwise.
-   * @param names names(alias) of component. Same as type field in the JS.
-   * @throws WXException Throws exception if type conflicts.
-   */
-  public static boolean registerComponent(Class<? extends WXComponent> clazz, boolean appendTree,String ... names) throws WXException {
-    if(clazz == null){
-      return false;
-    }
-    SimpleComponentHolder holder = new SimpleComponentHolder(clazz);
-    return registerComponent(holder,appendTree,names);
-  }
-
-
-  public static boolean registerComponent(IFComponentHolder holder, boolean appendTree, String ... names) throws WXException {
-    boolean result =  true;
-    try {
-      for (String name : names) {
-        Map<String, Object> componentInfo = new HashMap<>();
-        if (appendTree) {
-          componentInfo.put("append", "tree");
-        }
-        result = result && WXComponentRegistry.registerComponent(name, holder, componentInfo);
-      }
-      return result;
-    } catch (Throwable e) {
-      e.printStackTrace();
-      return result;
-    }
-  }
-
-  /**
-   * Register module. This is a wrapper method for
-   * {@link #registerModule(String, Class, boolean)}. The module register here only need to
-   * be singleton in {@link WXSDKInstance} level.
-   * @param moduleName  module name
-   * @param moduleClass module to be registered.
-   * @return true for registration success, false for otherwise.
-   * {@link WXModuleManager#registerModule(String, ModuleFactory, boolean)}
-   */
-  public static <T extends WXModule> boolean registerModule(String moduleName, Class<T> moduleClass,boolean global) throws WXException {
-    return moduleClass != null && registerModule(moduleName, new TypeModuleFactory<>(moduleClass), global);
-  }
-
-  /**
-   * Register module. This is a wrapper method for
-   * {@link #registerModule(String, Class, boolean)}. The module register here only need to
-   * be singleton in {@link WXSDKInstance} level.
-   * @param moduleName  module name
-   * @param factory module factory to be registered. You can override {@link DestroyableModuleFactory#buildInstance()} to customize module creation.
-   * @return true for registration success, false for otherwise.
-   * {@link WXModuleManager#registerModule(String, ModuleFactory, boolean)}
-   */
-  public static <T extends WXModule> boolean registerModuleWithFactory(String moduleName, DestroyableModuleFactory factory, boolean global) throws WXException {
-    return registerModule(moduleName, factory,global);
-  }
-
-
-  public static <T extends WXModule> boolean registerModuleWithFactory(String moduleName, IExternalModuleGetter factory, boolean global) throws WXException {
-    return registerModule(moduleName, factory.getExternalModuleClass(moduleName,WXEnvironment.getApplication()),global);
-  }
-
-  public static <T extends WXModule> boolean registerModule(String moduleName, ModuleFactory factory, boolean global) throws WXException {
-    return WXModuleManager.registerModule(moduleName, factory,global);
-  }
-
-  public static boolean registerModule(String moduleName, Class<? extends WXModule> moduleClass) throws WXException {
-    return registerModule(moduleName, moduleClass,false);
-  }
-
-  public static boolean registerService(String name, String serviceScript, Map<String, Object> options) {
-    return WXServiceManager.registerService(name, serviceScript, options);
-  }
-
-  public static boolean unRegisterService(String name) {
-    return WXServiceManager.unRegisterService(name);
-  }
-
-  /**
-   * module implement {@link Destroyable}
-   */
-  public static abstract class DestroyableModule extends WXModule implements Destroyable {}
-
-  public static  abstract  class DestroyableModuleFactory<T extends DestroyableModule> extends TypeModuleFactory<T> {
-    public DestroyableModuleFactory(Class<T> clz) {
-      super(clz);
-    }
-  }
-
-  public static void callback(String instanceId, String funcId, Map<String, Object> data) {
-    WXSDKManager.getInstance().callback(instanceId, funcId, data);
-  }
-
-  /**
-   * Model switch, only applicable for developer model
-   * @param debug
-   */
-  public static void restartBridge(boolean debug) {
-    WXEnvironment.sDebugMode = debug;
-    WXSDKManager.getInstance().restartBridge();
-  }
-
-  public static boolean registerComponent(String type, Class<? extends WXComponent> clazz) throws WXException {
-    return WXComponentRegistry.registerComponent(type, new SimpleComponentHolder(clazz),new HashMap<String, Object>());
-  }
-
-  public static boolean registerComponent(Map<String, Object> componentInfo, Class<? extends WXComponent> clazz) throws WXException {
-    if(componentInfo == null){
-      return false;
-    }
-    String type = (String)componentInfo.get("type");
-    if(TextUtils.isEmpty(type)){
-      return false;
-    }
-    return WXComponentRegistry.registerComponent(type,new SimpleComponentHolder(clazz), componentInfo);
-  }
-
-  public static void addCustomOptions(String key, String value) {
-    WXEnvironment.addCustomOptions(key, value);
-  }
-
-  public static IWXUserTrackAdapter getIWXUserTrackAdapter() {
-    return WXSDKManager.getInstance().getIWXUserTrackAdapter();
-  }
-
-  public static IWXImgLoaderAdapter getIWXImgLoaderAdapter() {
-    return WXSDKManager.getInstance().getIWXImgLoaderAdapter();
-  }
-
-  public static IDrawableLoader getDrawableLoader() {
-    return WXSDKManager.getInstance().getDrawableLoader();
-  }
-
-  public static IWXHttpAdapter getIWXHttpAdapter() {
-    return WXSDKManager.getInstance().getIWXHttpAdapter();
-  }
-
-  public static IWXStorageAdapter getIWXStorageAdapter() {
-    return WXSDKManager.getInstance().getIWXStorageAdapter();
-  }
-
-
-  public static IWXJsFileLoaderAdapter getIWXJsFileLoaderAdapter() {
-    return WXSDKManager.getInstance().getIWXJsFileLoaderAdapter();
-  }
-
-  public static IActivityNavBarSetter getActivityNavBarSetter() {
-    return WXSDKManager.getInstance().getActivityNavBarSetter();
-  }
-
-  public static INavigator getNavigator() {
-    return WXSDKManager.getInstance().getNavigator();
-  }
-
-  public static  void setNavigator(INavigator navigator) {
-    WXSDKManager.getInstance().setNavigator(navigator);
-  }
-
-  public static void setActivityNavBarSetter(IActivityNavBarSetter activityNavBarSetter) {
-    WXSDKManager.getInstance().setActivityNavBarSetter(activityNavBarSetter);
-  }
-
-  public static void reload(final Context context,String framework, boolean remoteDebug) {
-    WXEnvironment.sRemoteDebugMode = remoteDebug;
-    WXBridgeManager.getInstance().restart();
-    WXBridgeManager.getInstance().initScriptsFramework(framework);
-
-    WXServiceManager.reload();
-    WXModuleManager.reload();
-    WXComponentRegistry.reload();
-    WXSDKManager.getInstance().postOnUiThread(new Runnable() {
-      @Override
-      public void run() {
-        LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(JS_FRAMEWORK_RELOAD));
-      }
-    }, 0);
-  }
-  public static void reload(final Context context, boolean remoteDebug) {
-    reload(context,null,remoteDebug);
-  }
-
-  public static void reload() {
-    reload(WXEnvironment.getApplication(), WXEnvironment.sRemoteDebugMode);
-  }
-
-  public static void registerCoreEnv(String key, String value) {
-    WXBridgeManager.getInstance().registerCoreEnv(key, value);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
deleted file mode 100644
index cc3a8c8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
+++ /dev/null
@@ -1,2459 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import static com.taobao.weex.common.WXErrorCode.WX_ERR_RELOAD_PAGE;
-import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.support.annotation.WorkerThread;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import android.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ScrollView;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.adapter.IDrawableLoader;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.adapter.IWXImgLoaderAdapter;
-import com.taobao.weex.adapter.IWXJscProcessManager;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.appfram.websocket.IWebSocketAdapter;
-import com.taobao.weex.bridge.EventResult;
-import com.taobao.weex.bridge.NativeInvokeHelper;
-import com.taobao.weex.bridge.SimpleJSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.bridge.WXModuleManager;
-import com.taobao.weex.bridge.WXParams;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.Destroyable;
-import com.taobao.weex.common.OnWXScrollListener;
-import com.taobao.weex.common.RenderTypes;
-import com.taobao.weex.common.WXConfig;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.common.WXPerformance;
-import com.taobao.weex.common.WXRefreshData;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.http.WXHttpUtil;
-import com.taobao.weex.instance.InstanceOnFireEventInterceptor;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.performance.WXStateRecord;
-import com.taobao.weex.performance.WhiteScreenUtils;
-import com.taobao.weex.render.WXAbstractRenderContainer;
-import com.taobao.weex.tracing.WXTracing;
-import com.taobao.weex.ui.action.GraphicActionAddElement;
-import com.taobao.weex.ui.component.NestedContainer;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXEmbed;
-import com.taobao.weex.ui.flat.FlatGUIContext;
-import com.taobao.weex.ui.view.WXScrollView;
-import com.taobao.weex.utils.Trace;
-import com.taobao.weex.utils.WXDeviceUtils;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXFileUtils;
-import com.taobao.weex.utils.WXJsonUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXReflectionUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import com.taobao.weex.utils.cache.RegisterCache;
-import com.taobao.weex.utils.tools.LogDetail;
-import com.taobao.weex.utils.tools.TimeCalculator;
-import java.io.Serializable;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.PriorityQueue;
-import java.util.concurrent.ConcurrentHashMap;
-
-
-/**
- * Each instance of WXSDKInstance represents an running weex instance.
- * It can be a pure weex view, or mixed with native view
- */
-public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChangeListener {
-
-  private static  final  String SOURCE_TEMPLATE_BASE64_MD5 = "templateSourceBase64MD5";
-
-  /**
-   * Devtool protocol
-   */
-  public static String ACTION_DEBUG_INSTANCE_REFRESH = "DEBUG_INSTANCE_REFRESH";
-  public static String ACTION_INSTANCE_RELOAD = "INSTANCE_RELOAD";
-
-  //Performance
-  public boolean mEnd = false;
-  public boolean mHasCreateFinish = false;
-  public static final String BUNDLE_URL = "bundleUrl";
-  private IWXUserTrackAdapter mUserTrackAdapter;
-  private IWXRenderListener mRenderListener;
-  private IWXStatisticsListener mStatisticsListener;
-  /** package **/ Context mContext;
-  private final String mInstanceId;
-  private WXAbstractRenderContainer mRenderContainer;
-  private WXComponent mRootComp;
-  private boolean mRendered;
-  private WXRefreshData mLastRefreshData;
-  private NestedInstanceInterceptor mNestedInstanceInterceptor;
-  private String mBundleUrl = "";
-  public static String requestUrl = "requestUrl";
-  private boolean isDestroy=false;
-  private boolean hasException = false;
-  private boolean isRenderSuccess = false;
-  private boolean createInstanceHeartBeat = false;
-  private Map<String,Serializable> mUserTrackParams;
-  private NativeInvokeHelper mNativeInvokeHelper;
-  private boolean isCommit=false;
-  private WXGlobalEventReceiver mGlobalEventReceiver=null;
-  private boolean trackComponent;
-  private boolean enableLayerType = true;
-  private boolean mNeedValidate = false;
-  private boolean mNeedReLoad = false;
-  private boolean mUseScroller = false;
-  private int mInstanceViewPortWidth = 750;
-  private boolean enableFullScreenHeight = false;
-  private WXInstanceApm mApmForInstance;
-  private @NonNull
-  FlatGUIContext mFlatGUIContext =new FlatGUIContext();
-
-  private Map<String,String> mContainerInfo;
-
-  public boolean isNewFsEnd = false;
-  private List<JSONObject> componentsInfoExceedGPULimit  = new LinkedList<>();
-
-  /**
-   * bundle type
-   */
-  public WXBridgeManager.BundType bundleType;
-  public long mRenderStartNanos;
-  public int mExecJSTraceId = WXTracing.nextId();
-
-  private boolean isViewDisAppear = false;
-
-  /**
-   *for network tracker
-   */
-  public String mwxDims[] = new String [5];
-  public long measureTimes[] = new long [5];
-
-  public WeakReference<String> templateRef;
-  public Map<String,List<String>> responseHeaders = new HashMap<>();
-
-  /**
-   * Render strategy.
-   */
-  private WXRenderStrategy mRenderStrategy = WXRenderStrategy.APPEND_ASYNC;
-
-  private boolean mDisableSkipFrameworkInit = false;
-
-  /**
-   * Render start time
-   */
-  public long mRenderStartTime;
-  /**
-   * Refresh start time
-   */
-  private long mRefreshStartTime;
-  private WXPerformance mWXPerformance;
-  private ScrollView mScrollView;
-  private WXScrollView.WXScrollViewListener mWXScrollViewListener;
-
-  private List<OnWXScrollListener> mWXScrollListeners;
-
-  private List<String> mLayerOverFlowListeners;
-
-  private List<ActionBarHandler> mWXActionbarHandlers;
-
-  private List<OnBackPressedHandler> mWXBackPressedHandlers;
-
-  private List<OnActivityResultHandler> mWXOnActivityResultHandlers;
-
-  private WXSDKInstance mParentInstance;
-
-  private String mRenderType = RenderTypes.RENDER_TYPE_NATIVE;
-
-  public TimeCalculator mTimeCalculator;
-  /**
-   * Default Width And Viewport is 750,
-   * when screen width change, we adjust viewport to adapter screen change
-   * */
-  private boolean mAutoAdjustDeviceWidth = WXEnvironment.AUTO_ADJUST_ENV_DEVICE_WIDTH;
-
-  public  List<JSONObject> getComponentsExceedGPULimit(){return componentsInfoExceedGPULimit;}
-  @RestrictTo(Scope.LIBRARY)
-  public void setComponentsInfoExceedGPULimit(JSONObject component){
-    if(component!= null && !component.isEmpty()){
-      componentsInfoExceedGPULimit.add(component);
-    }
-  }
-
-  public List<String> getLayerOverFlowListeners() {
-    return mLayerOverFlowListeners;
-  }
-
-  public void addLayerOverFlowListener(String ref) {
-    if (mLayerOverFlowListeners == null)
-      mLayerOverFlowListeners = new ArrayList<>();
-    mLayerOverFlowListeners.add(ref);
-  }
-
-  public void removeLayerOverFlowListener(String ref) {
-    if (mLayerOverFlowListeners != null)
-      mLayerOverFlowListeners.remove(ref);
-  }
-
-  /**
-   * whether we are in preRender mode
-   * */
-  private volatile boolean isPreRenderMode;
-
-  private boolean mCurrentGround = false;
-  private ComponentObserver mComponentObserver;
-  private Map<String, GraphicActionAddElement> inactiveAddElementAction = new ArrayMap<>();
-
-  private Map<Long, ContentBoxMeasurement> mContentBoxMeasurements = new ArrayMap<>();
-
-  private List<InstanceOnFireEventInterceptor> mInstanceOnFireEventInterceptorList;
-
-
-  /**
-   * network handler
-   */
-  public interface ImageNetworkHandler {
-    public String fetchLocal(String url);
-  }
-
-  public interface StreamNetworkHandler {
-    public String fetchLocal(String url);
-  }
-
-  public interface CustomFontNetworkHandler {
-    public String fetchLocal(String url);
-  }
-
-  private ImageNetworkHandler mImageNetworkHandler;
-
-  private StreamNetworkHandler mStreamNetworkHandler;
-
-  private CustomFontNetworkHandler mCustomFontNetworkHandler;
-
-  public ImageNetworkHandler getImageNetworkHandler() {
-    return mImageNetworkHandler;
-  }
-
-  public void setImageNetworkHandler(ImageNetworkHandler imageNetworkHandler) {
-    this.mImageNetworkHandler = imageNetworkHandler;
-  }
-
-  public StreamNetworkHandler getStreamNetworkHandler() {
-    return mStreamNetworkHandler;
-  }
-
-  public void setStreamNetworkHandler(StreamNetworkHandler streamNetworkHandler) {
-    this.mStreamNetworkHandler = streamNetworkHandler;
-  }
-
-  public CustomFontNetworkHandler getCustomFontNetworkHandler() {
-    return mCustomFontNetworkHandler;
-  }
-
-  public void setCustomFontNetworkHandler(CustomFontNetworkHandler customFontNetworkHandler) {
-    this.mCustomFontNetworkHandler = customFontNetworkHandler;
-  }
-
-
-  /**
-   *  ActionBar Handler
-   */
-
-  public interface ActionBarHandler {
-    boolean onSupportNavigateUp();
-  }
-
-  public interface OnBackPressedHandler {
-    boolean onBackPressed();
-  }
-
-  public static abstract class OnActivityResultHandler {
-    private String id;
-
-    public OnActivityResultHandler(String id) {
-      this.id = id;
-    }
-
-    public abstract boolean onActivityResult(int requestCode, int resultCode, Intent data, String id);
-
-    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
-      return onActivityResult(requestCode, resultCode, data, id);
-    }
-  }
-
-  /**
-   * set make weexCore run in single process mode
-   * @param flag true means weexCore run in single process mode or multi process mode
-   */
-  public void setUseSingleProcess(boolean flag) {
-    WXBridgeManager.getInstance().setUseSingleProcess(flag);
-  }
-
-  /**
-   * set open SandBox
-   * @param flag
-   */
-  public void setUseSandBox(boolean flag) {
-    WXBridgeManager.getInstance().setSandBoxContext(flag);
-  }
-
-  public PriorityQueue<WXEmbed> hiddenEmbeds;
-
-  private int maxHiddenEmbedsNum = -1; //max hidden embed num, -1 standard for ulimit
-
-  public int getMaxHiddenEmbedsNum() {
-    return maxHiddenEmbedsNum;
-  }
-
-  public void setMaxHiddenEmbedsNum(int maxHiddenEmbedsNum) {
-    this.maxHiddenEmbedsNum = maxHiddenEmbedsNum;
-  }
-
-  @WorkerThread
-  @RestrictTo(Scope.LIBRARY)
-  public void addInActiveAddElementAction(String ref, GraphicActionAddElement action){
-    inactiveAddElementAction.put(ref, action);
-  }
-
-  @WorkerThread
-  @RestrictTo(Scope.LIBRARY)
-  public void removeInActiveAddElmentAction(String ref){
-    inactiveAddElementAction.remove(ref);
-  }
-
-  @WorkerThread
-  @RestrictTo(Scope.LIBRARY)
-  public GraphicActionAddElement getInActiveAddElementAction(String ref){
-    return inactiveAddElementAction.get(ref);
-  }
-
-  /**
-   * If anchor is created manually(etc. define a layout xml resource ),
-   * be aware do not add it to twice when {@link IWXRenderListener#onViewCreated(WXSDKInstance, View)}.
-   * @param a
-   */
-  public void setRenderContainer(RenderContainer a){
-     setWXAbstractRenderContainer(a);
-  }
-
-  public void setWXAbstractRenderContainer(WXAbstractRenderContainer a){
-    if(a != null) {
-      a.setSDKInstance(this);
-      a.addOnLayoutChangeListener(this);
-    }
-
-    mRenderContainer = a;
-    if (mRenderContainer != null && mRenderContainer.getLayoutParams() != null
-            && mRenderContainer.getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
-      WXBridgeManager.getInstance().post(new Runnable() {
-        @Override
-        public void run() {
-          WXBridgeManager.getInstance().setRenderContentWrapContentToCore(true, getInstanceId());
-        }
-      });
-    } else {
-      WXBridgeManager.getInstance().post(new Runnable() {
-        @Override
-        public void run() {
-          WXBridgeManager.getInstance().setRenderContentWrapContentToCore(false, getInstanceId());
-        }
-      });
-    }
-  }
-
-  private int mMaxDeepLayer;
-
-  public boolean isTrackComponent() {
-    return trackComponent;
-  }
-
-  public void setTrackComponent(boolean trackComponent) {
-    this.trackComponent = trackComponent;
-  }
-
-  /**
-   * Tell whether it is enabled to change the layerType
-   * {@link android.view.View#setLayerType(int, Paint)}
-   * @return True for enable to change the layerType of component, false otherwise. The default
-   * is True
-   */
-  public boolean isLayerTypeEnabled() {
-    return enableLayerType;
-  }
-
-  /**
-   * Enable the ability of changing layerType. e.g. {@link android.view.View#setLayerType(int, Paint)}
-   * Disable the ability of changing layerType will have tremendous <strong>performance
-   * punishment</strong>.
-   *
-   * <strong>Do not</strong> set this to false unless you know exactly what you are doing.
-   * @param enable True for enable to change the layerType of component, false otherwise. The default
-   * is True
-   */
-  public void enableLayerType(boolean enable) {
-    enableLayerType = enable;
-  }
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public @NonNull
-  FlatGUIContext getFlatUIContext(){
-    return mFlatGUIContext;
-  }
-
-  public boolean isNeedValidate() {
-    return mNeedValidate;
-  }
-
-  public boolean isNeedReLoad() {
-    return mNeedReLoad;
-  }
-
-  public void setNeedLoad(boolean load) {
-    mNeedReLoad = load;
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  public void  setEnableFullScreenHeight(boolean fullScreenHeight){enableFullScreenHeight = fullScreenHeight;}
-
-  @RestrictTo(Scope.LIBRARY)
-  public boolean isFullScreenHeightEnabled(){return enableFullScreenHeight;}
-
-  public boolean isUseScroller() {
-    return mUseScroller;
-  }
-
-  public void setUseScroller(boolean use) {
-    mUseScroller = use;
-  }
-
-  public void setInstanceViewPortWidth(int instanceViewPortWidth) {
-    setInstanceViewPortWidth(instanceViewPortWidth,false);
-
-  }
-  public void setInstanceViewPortWidth(int instanceViewPortWidth,boolean fromMetaModule){
-    this.mInstanceViewPortWidth = instanceViewPortWidth;
-    this.mAutoAdjustDeviceWidth = false;
-    if(!fromMetaModule){
-      WXBridgeManager.getInstance().setViewPortWidth(getInstanceId(), mInstanceViewPortWidth);
-    }
-  }
-  public void resetDeviceDisplayOfPage(){
-    WXBridgeManager.getInstance().setDeviceDisplayOfPage(getInstanceId(), WXViewUtils.getScreenWidth(getContext()), WXViewUtils.getScreenHeight(getContext()));
-  }
-  public void setPageKeepRawCssStyles(){
-    WXBridgeManager.getInstance().setPageArgument(getInstanceId(),"reserveCssStyles","true");
-  }
-  public void reloadPageLayout(){
-    WXBridgeManager.getInstance().reloadPageLayout(getInstanceId());
-  }
-
-  public void setAutoAdjustDeviceWidth(boolean autoAdjustViewPort){
-    this.mAutoAdjustDeviceWidth = autoAdjustViewPort;
-  }
-
-  public boolean isAutoAdjustDeviceWidth(){
-    return mAutoAdjustDeviceWidth;
-  }
-
-  private void setDeviceDisplay(float deviceWith, float deviceHeight, float scale){
-    WXBridgeManager.getInstance().setDeviceDisplay(getInstanceId(), deviceWith, deviceHeight, scale);
-  }
-
-
-
-  public int getInstanceViewPortWidth(){
-    return mInstanceViewPortWidth;
-  }
-
-  public interface OnInstanceVisibleListener{
-    void onAppear();
-    void onDisappear();
-  }
-  private List<OnInstanceVisibleListener> mVisibleListeners = new ArrayList<>();
-
-  public WXSDKInstance(Context context) {
-    mInstanceId = WXSDKManager.getInstance().generateInstanceId();
-    init(context);
-  }
-
-  //for preInit
-  public WXSDKInstance(){
-    mInstanceId = WXSDKManager.getInstance().generateInstanceId();
-    mWXPerformance = new WXPerformance(mInstanceId);
-    mApmForInstance = new WXInstanceApm(mInstanceId);
-    WXSDKManager.getInstance().getAllInstanceMap().put(mInstanceId,this);
-    mTimeCalculator = new TimeCalculator(this);
-  }
-
-
-  /**
-   * For unittest only.
-   */
-  @RestrictTo(Scope.TESTS)
-  WXSDKInstance(Context context,String id) {
-    mInstanceId = id;
-    init(context);
-  }
-
-  public WXComponent getRootComponent() {
-    return mRootComp;
-  }
-
-  public void setNestedInstanceInterceptor(NestedInstanceInterceptor interceptor){
-    mNestedInstanceInterceptor = interceptor;
-  }
-
-  public final WXSDKInstance createNestedInstance(NestedContainer container){
-    WXSDKInstance sdkInstance = newNestedInstance();
-    if(mNestedInstanceInterceptor != null){
-      mNestedInstanceInterceptor.onCreateNestInstance(sdkInstance,container);
-    }
-    if(sdkInstance != null){
-        sdkInstance.setComponentObserver(this.getComponentObserver());
-    }
-    return sdkInstance;
-  }
-
-  protected WXSDKInstance newNestedInstance() {
-    return new WXSDKInstance(mContext);
-  }
-  public boolean isHasException() {
-    return hasException;
-  }
-
-  public void setHasException(boolean hasException) {
-    this.hasException = hasException;
-  }
-
-  public void createInstanceFuncHeartBeat() {
-    WXLogUtils.d("createInstanceFuncHeartBeat: " + mInstanceId);
-    this.createInstanceHeartBeat = true;
-    getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_END_EXCUTE_BUNDLE);
-  }
-
-  public void addOnInstanceVisibleListener(OnInstanceVisibleListener l){
-    mVisibleListeners.add(l);
-  }
-
-  public void removeOnInstanceVisibleListener(OnInstanceVisibleListener l){
-    mVisibleListeners.remove(l);
-  }
-
-  public void init(Context context) {
-    RegisterCache.getInstance().idle(true);
-    mContext = context;
-    mContainerInfo = new HashMap<>(4);
-    mNativeInvokeHelper = new NativeInvokeHelper(mInstanceId);
-
-    if (null == mWXPerformance){
-      mWXPerformance = new WXPerformance(mInstanceId);
-    }
-    if (null == mApmForInstance){
-      mApmForInstance = new WXInstanceApm(mInstanceId);
-    }
-
-    mWXPerformance.WXSDKVersion = WXEnvironment.WXSDK_VERSION;
-    mWXPerformance.JSLibInitTime = WXEnvironment.sJSLibInitTime;
-
-    mUserTrackAdapter=WXSDKManager.getInstance().getIWXUserTrackAdapter();
-
-    WXSDKManager.getInstance().getAllInstanceMap().put(mInstanceId,this);
-
-    mContainerInfo.put(WXInstanceApm.KEY_PAGE_PROPERTIES_CONTAINER_NAME, context instanceof Activity
-            ? context.getClass().getSimpleName()
-            :"unKnowContainer"
-    );
-    mContainerInfo.put(WXInstanceApm.KEY_PAGE_PROPERTIES_INSTANCE_TYPE,"page");
-
-    // WXBridgeManager.getInstance().checkJsEngineMultiThread();
-    mDisableSkipFrameworkInit = isDisableSkipFrameworkInDataRender();
-
-    if(mTimeCalculator == null) {
-      mTimeCalculator = new TimeCalculator(this);
-    }
-  }
-
-  /**
-   * Set a Observer for component.
-   * This observer will be called in each component, should not doing
-   * anything will impact render performance.
-   *
-   * @param observer
-   */
-  public void setComponentObserver(ComponentObserver observer){
-    mComponentObserver = observer;
-  }
-
-  public ComponentObserver getComponentObserver(){
-    return mComponentObserver;
-  }
-
-  public NativeInvokeHelper getNativeInvokeHelper() {
-    return mNativeInvokeHelper;
-  }
-
-  @Deprecated
-  public void setBizType(String bizType) {
-    if (!TextUtils.isEmpty(bizType)) {
-      mWXPerformance.bizType = bizType;
-    }
-  }
-
-  public ScrollView getScrollView() {
-    return mScrollView;
-  }
-
-  public void setRootScrollView(ScrollView scrollView) {
-    mScrollView = scrollView;
-    if (mWXScrollViewListener != null && mScrollView instanceof WXScrollView) {
-      ((WXScrollView) mScrollView).addScrollViewListener(mWXScrollViewListener);
-    }
-  }
-
-  @Deprecated
-  public void registerScrollViewListener(WXScrollView.WXScrollViewListener scrollViewListener) {
-    mWXScrollViewListener = scrollViewListener;
-  }
-
-  @Deprecated
-  public WXScrollView.WXScrollViewListener getScrollViewListener() {
-    return mWXScrollViewListener;
-  }
-
-  @Deprecated
-  public void setIWXUserTrackAdapter(IWXUserTrackAdapter adapter) {
-  }
-
-  public void setContainerInfo(String key,String val){
-    mContainerInfo.put(key,val);
-  }
-
-  public Map<String, String> getContainerInfo() {
-    return mContainerInfo;
-  }
-
-  /**
-   * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy
-   * @param template bundle js
-   * @param options  os   iphone/android/ipad
-   *                 weexversion    Weex version(like 1.0.0)
-   *                 appversion     App version(like 1.0.0)
-   *                 devid        Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH)
-   *                 sysversion    Device system version(like 5.4.4、7.0.4, should be used with os)
-   *                 sysmodel     Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE")
-   *                 Time    UNIX timestamp, UTC+08:00
-   *                 TTID(Optional)
-   *                 MarkertId
-   *                 Appname(Optional)  tm,tb,qa
-   *                 Bundleurl(Optional)  template url
-   * @param jsonInitData Initial data for rendering
-   */
-  public void render(String template, Map<String, Object> options, String jsonInitData) {
-    render(template, options, jsonInitData, WXRenderStrategy.APPEND_ASYNC);
-  }
-
-  /**
-   * Render template asynchronously
-   * @param template bundle js
-   * @param options  os   iphone/android/ipad
-   *                 weexversion    Weex version(like 1.0.0)
-   *                 appversion     App version(like 1.0.0)
-   *                 devid        Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH)
-   *                 sysversion    Device system version(like 5.4.4、7.0.4, should be used with os)
-   *                 sysmodel     Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE")
-   *                 Time    UNIX timestamp, UTC+08:00
-   *                 TTID(Optional)
-   *                 MarkertId
-   *                 Appname(Optional)  tm,tb,qa
-   *                 Bundleurl(Optional)  template url
-   * @param jsonInitData Initial data for rendering
-   * @param flag     RenderStrategy {@link WXRenderStrategy}
-   */
-  @Deprecated
-  public void render(String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) {
-    render(WXPerformance.DEFAULT, template, options, jsonInitData, flag);
-  }
-
-  /**
-   * Render template asynchronously
-   *
-   * @param pageName, used for performance log.
-   * @param template bundle js
-   * @param options  os   iphone/android/ipad
-   *                 weexversion    Weex version(like 1.0.0)
-   *                 appversion     App version(like 1.0.0)
-   *                 devid        Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH)
-   *                 sysversion    Device system version(like 5.4.4、7.0.4, should be used with os)
-   *                 sysmodel     Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE")
-   *                 Time    UNIX timestamp, UTC+08:00
-   *                 TTID(Optional)
-   *                 MarkertId
-   *                 Appname(Optional)  tm,tb,qa
-   *                 Bundleurl(Optional)  template url
-   * @param jsonInitData Initial data for rendering
-   * @param flag     RenderStrategy {@link WXRenderStrategy}
-   */
-  public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) {
-    render(pageName, new Script(template), options, jsonInitData, flag);
-  }
-
-  public void render(String pageName, Script template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) {
-    mWXPerformance.beforeInstanceRender(mInstanceId);
-
-    if(WXEnvironment.isApkDebugable() && WXPerformance.DEFAULT.equals(pageName)){
-
-      if (getUIContext() != null) {
-        new AlertDialog.Builder(getUIContext())
-                .setTitle("Error: Missing pageName")
-                .setMessage("We highly recommend you to set pageName. Call" +
-                        "\nWXSDKInstance#render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag)\n" +
-                        "to fix it.")
-                .show();
-      }
-
-      return;
-    }
-    renderInternal(pageName,template,options,jsonInitData,flag);
-  }
-
-  /**
-   * Render binary template asynchronously in DATA_RENDER_BINARY strategy.
-   */
-  public void render(String pageName, byte[] template, Map<String, Object> options, String jsonInitData) {
-    render(pageName, new Script(template), options, jsonInitData, WXRenderStrategy.DATA_RENDER_BINARY);
-  }
-
-  private void ensureRenderArchor(){
-    if(mRenderContainer == null){
-      if (getContext() != null) {
-        setRenderContainer(new RenderContainer(getContext()));
-        mRenderContainer.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
-        mRenderContainer.setBackgroundColor(Color.TRANSPARENT);
-        mRenderContainer.setSDKInstance(this);
-        mRenderContainer.addOnLayoutChangeListener(this);
-      }
-    }
-  }
-
-  private void renderInternal(String pageName,
-                              String template,
-                              Map<String, Object> options,
-                              String jsonInitData,
-                              WXRenderStrategy flag) {
-    if (mRendered || TextUtils.isEmpty(template)) {
-      return;
-    }
-    renderInternal(pageName, new Script(template), options, jsonInitData, flag);
-  }
-
-  private boolean isPreInit = false;
-  public boolean isPreInitMode(){
-    return isPreInit;
-  }
-
-  private boolean isPreDownLoad =false;
-  public boolean isPreDownLoad(){
-    return isPreDownLoad;
-  }
-
-  public void onInstanceReady(){
-    WXLogUtils.d("test->","onInstanceReady");
-    mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_CONTAINER_READY);
-    if (!isPreInit && !isPreDownLoad){
-      return;
-    }
-    mApmForInstance.onInstanceReady(isPreDownLoad);
-    if (isPreDownLoad){
-        mHttpListener.onInstanceReady();
-    }
-  }
-
-  public void preInit(String pageName,
-                      String script,
-                      Map<String, Object> options,
-                      String jsonInitData,
-                      WXRenderStrategy flag){
-    isPreInit = true;
-    mRenderStrategy = flag;
-    Map<String, Object> renderOptions = options;
-    if (renderOptions == null) {
-      renderOptions = new HashMap<>();
-    }
-    //mApmForInstance.doInit();
-    mApmForInstance.isReady = false;
-    WXSDKManager.getInstance().createInstance(this, new Script(script), renderOptions, jsonInitData);
-  }
-
-  public void preDownLoad(String url,
-                          Map<String, Object> options,
-                          String jsonInitData,
-                          WXRenderStrategy flag){
-    this.isPreDownLoad =true;
-    mRenderStrategy = flag;
-    mApmForInstance.isReady = false;
-    renderByUrl(url,url,options,jsonInitData,flag);
-  }
-
-
-  private void renderInternal(String pageName,
-                              Script template,
-                              Map<String, Object> options,
-                              String jsonInitData,
-                              WXRenderStrategy flag){
-    if (mRendered || template == null || template.isEmpty()) {
-      return;
-    }
-
-    LogDetail logDetail = mTimeCalculator.createLogDetail("renderInternal");
-    mRenderStrategy = flag;
-
-    //some case ,from render(template),but not render (url)
-    if (!mApmForInstance.hasInit()){
-      mApmForInstance.doInit();
-    }
-    mApmForInstance.setPageName(pageName);
-    mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN);
-    mApmForInstance.doDelayCollectData();
-
-    mWXPerformance.pageName = (TextUtils.isEmpty(pageName) ? "defaultBundleUrl":pageName);
-    if (TextUtils.isEmpty(mBundleUrl)) {
-      mBundleUrl = mWXPerformance.pageName;
-    }
-
-    if (WXTracing.isAvailable()) {
-      WXTracing.TraceEvent traceEvent = WXTracing.newEvent("executeBundleJS", mInstanceId, -1);
-      traceEvent.traceId = mExecJSTraceId;
-      traceEvent.iid = mInstanceId;
-      traceEvent.tname = "JSThread";
-      traceEvent.ph = "B";
-      traceEvent.submit();
-      mRenderStartNanos = System.nanoTime();
-    }
-
-    ensureRenderArchor();
-
-    Map<String, Object> renderOptions = options;
-    if (renderOptions == null) {
-      renderOptions = new HashMap<>();
-    }
-
-    if (WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && renderOptions.get("dynamicMode") == null) {
-      renderOptions.put("dynamicMode", "true");
-      renderByUrl(pageName, WXEnvironment.sDynamicUrl, renderOptions, jsonInitData, flag);
-      return;
-    }
-
-    TimeCalculator timeCalculator = new TimeCalculator(this);
-
-    mWXPerformance.JSTemplateSize = template.length() / 1024f;
-    mApmForInstance.addStats(WXInstanceApm.KEY_PAGE_STATS_BUNDLE_SIZE,mWXPerformance.JSTemplateSize);
-    mRenderStartTime = System.currentTimeMillis();
-    WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName);
-    if(mAutoAdjustDeviceWidth && WXDeviceUtils.isAutoResize(mContext)){
-         if(WXEnvironment.AUTO_UPDATE_APPLICATION_SCREEN_SIZE) {
-             WXViewUtils.updateApplicationScreen(mContext);
-         }
-         WXParams params = WXBridgeManager.getInstance().getInitParams();
-         if(params != null && !TextUtils.equals(params.getDeviceWidth(), String.valueOf(WXViewUtils.getScreenWidth(mContext)))){
-           params.setDeviceWidth(String.valueOf(WXViewUtils.getScreenWidth(mContext)));
-           params.setDeviceHeight(String.valueOf(WXViewUtils.getScreenHeight(mContext)));
-           float density = WXEnvironment.sApplication.getResources().getDisplayMetrics().density;
-           WXEnvironment.addCustomOptions(WXConfig.scale, Float.toString(density));
-           String statusBarHeight =  null;
-           if(WXViewUtils.getStatusBarHeight(mContext) > 0 ){
-             statusBarHeight = String.valueOf(WXViewUtils.getStatusBarHeight(mContext));
-           }
-           WXBridgeManager.getInstance().updateInitDeviceParams(params.getDeviceWidth(),
-                                                                params.getDeviceHeight(),
-                                                                Float.toString(density), statusBarHeight);
-           setDeviceDisplay(WXViewUtils.getScreenWidth(mContext),
-                            WXViewUtils.getScreenHeight(mContext),
-                            WXViewUtils.getScreenDensity(mContext));
-         }
-    }
-    logDetail.taskStart();
-    if (isPreInitMode()){
-      getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_START);
-      WXBridgeManager.getInstance().loadJsBundleInPreInitMode(getInstanceId(),template.getContent());
-    } else {
-      WXSDKManager.getInstance().createInstance(this, template, renderOptions, jsonInitData);
-    }
-    logDetail.taskEnd();
-    mRendered = true;
-
-    final IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
-
-    if(wxJscProcessManager != null && wxJscProcessManager.shouldReboot()) {
-      WXSDKManager.getInstance().postOnUiThread(new Runnable() {
-        @Override
-        public void run() {
-          checkWhiteScreen();
-          if(isDestroy || hasException || isRenderSuccess) {
-            return;
-          }
-
-          // there is no need to reboot js engine if render by eagle
-          if(isDataRender()) {
-            return;
-          }
-
-          View containerView = getContainerView();
-          if(containerView instanceof ViewGroup) {
-            if(0 == ((ViewGroup) containerView).getChildCount()) {
-              if(wxJscProcessManager.withException(WXSDKInstance.this)) {
-                onJSException(String.valueOf(WX_ERR_RELOAD_PAGE),"jsc reboot","jsc reboot");
-              }
-              if(!createInstanceHeartBeat) {
-                  WXBridgeManager.getInstance().callReportCrashReloadPage(mInstanceId, null);
-                  WXLogUtils.e("callReportCrashReloadPage with jsc reboot");
-              }
-            }
-          }
-        }
-      }, wxJscProcessManager.rebootTimeout());
-    }
-  }
-
-
-  private void checkWhiteScreen(){
-    if (isDestroy ||!WhiteScreenUtils.doWhiteScreenCheck()){
-      return;
-    }
-
-    boolean isWS = WhiteScreenUtils.isWhiteScreen(this);
-    if (!isWS){
-      return;
-    }
-    WXErrorCode errorCode = createInstanceHeartBeat?WXErrorCode.WX_ERROR_WHITE_SCREEN:WXErrorCode.WHITE_SCREEN_RESPONSE_TIMEOUT;
-    if (WXBridgeManager.getInstance().isRebootExceedLimit()){
-      errorCode = WXErrorCode.WHITE_SCREEN_REBOOT_EXCEED_LIMIT;
-    }
-    Map<String,String> args = new HashMap<>(1);
-    String vieTreeMsg = WhiteScreenUtils.takeViewTreeSnapShot(this);
-    args.put("viewTree",null == vieTreeMsg?"null viewTreeMsg":vieTreeMsg);
-    args.put("weexCoreThreadStackTrace",WXBridgeManager.getInstance().getWeexCoreThreadStackTrace());
-
-    for (Map.Entry<String,String> entry: WXStateRecord.getInstance().getStateInfo().entrySet()){
-      args.put(entry.getKey(),entry.getValue());
-    }
-    WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),errorCode,"checkEmptyScreen",errorCode.getErrorMsg(),args);
-  }
-
-
-  public boolean skipFrameworkInit(){
-    return isDataRender() && !mDisableSkipFrameworkInit;
-  }
-
-  private boolean isDataRender() {
-    return getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY || getRenderStrategy() == WXRenderStrategy.DATA_RENDER;
-  }
-
-  private void renderByUrlInternal(String pageName,
-                                   final String url,
-                                   Map<String, Object> options,
-                                   final String jsonInitData,
-                                   WXRenderStrategy flag) {
-
-
-    LogDetail logDetail = mTimeCalculator.createLogDetail("renderByUrlInternal");
-    logDetail.taskStart();
-    ensureRenderArchor();
-    pageName = wrapPageName(pageName, url);
-    mBundleUrl = url;
-    mRenderStrategy = flag;
-    if(WXSDKManager.getInstance().getValidateProcessor()!=null) {
-      mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl);
-    }
-
-    Map<String, Object> renderOptions = options;
-    if (renderOptions == null) {
-      renderOptions = new HashMap<>();
-    }
-    if (!renderOptions.containsKey(BUNDLE_URL)) {
-      renderOptions.put(BUNDLE_URL, url);
-    }
-
-    getWXPerformance().pageName = pageName;
-
-    mApmForInstance.doInit();
-    mApmForInstance.setPageName(pageName);
-
-    Uri uri = Uri.parse(url);
-    if (uri != null && TextUtils.equals(uri.getScheme(), "file")) {
-      mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
-      String template = WXFileUtils.loadFileOrAsset(assembleFilePath(uri), mContext);
-      mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END);
-      render(pageName,template , renderOptions, jsonInitData, flag);
-      return;
-    }
-
-    boolean is_wlasm = false;
-    if (uri != null && uri.getPath()!=null) {
-      if(uri.getPath().endsWith(".wlasm")){
-        is_wlasm =  true;
-      }
-    }
-    if (is_wlasm){
-      flag = WXRenderStrategy.DATA_RENDER_BINARY;
-    }
-
-    IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter();
-
-    WXRequest wxRequest = new WXRequest();
-    wxRequest.url = rewriteUri(Uri.parse(url),URIAdapter.BUNDLE).toString();
-    if(wxRequest != null && !TextUtils.isEmpty(wxRequest.url)){
-      requestUrl = wxRequest.url;
-    }else {
-      requestUrl = pageName;
-    }
-
-    if (wxRequest.paramMap == null) {
-      wxRequest.paramMap = new HashMap<String, String>();
-    }
-    wxRequest.instanceId = getInstanceId();
-    wxRequest.paramMap.put(KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(mContext,WXEnvironment.getConfig()));
-    wxRequest.paramMap.put("isBundleRequest","true");
-    mHttpListener = new WXHttpListener(this, pageName, renderOptions, jsonInitData, flag, System.currentTimeMillis());
-    mHttpListener.isPreDownLoadMode = isPreDownLoad;
-    mHttpListener.setSDKInstance(this);
-    mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
-    adapter.sendRequest(wxRequest, (IWXHttpAdapter.OnHttpListener) mHttpListener);
-    logDetail.taskEnd();
-  }
-
-  private WXHttpListener mHttpListener = null;
-
-  /**
-   * Use {@link #render(String, String, Map, String, WXRenderStrategy)} instead.
-   * @param pageName
-   * @param template
-   * @param options
-   * @param jsonInitData
-   * @param width
-   * @param height
-   * @param flag
-   */
-  @Deprecated
-  public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, int width, int height, WXRenderStrategy flag) {
-    render(pageName,template,options,jsonInitData,flag);
-  }
-
-  /**
-   * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy
-   * @param template bundle js
-   */
-  public void render(String template) {
-    render(WXPerformance.DEFAULT, template, null, null, mRenderStrategy);
-  }
-
-  /**
-   * Use {@link #render(String)} instead.
-   * @param template
-   * @param width
-   * @param height
-   */
-  @Deprecated
-  public void render(String template, int width, int height) {
-    render(template);
-  }
-
-  /**
-   * Use {@link #renderByUrl(String, String, Map, String, WXRenderStrategy)} instead.
-   * @param pageName
-   * @param url
-   * @param options
-   * @param jsonInitData
-   * @param width
-   * @param height
-   * @param flag
-   */
-  @Deprecated
-  public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final int width, final int height, final WXRenderStrategy flag){
-    renderByUrl(pageName,url,options,jsonInitData,flag);
-  }
-
-  public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final WXRenderStrategy flag) {
-    renderByUrlInternal(pageName,url,options,jsonInitData,flag);
-  }
-
-  private String wrapPageName(String pageName, String url) {
-    if(TextUtils.equals(pageName, WXPerformance.DEFAULT)){
-      pageName = url;
-      WXExceptionUtils.degradeUrl = pageName;
-      try {
-        Uri uri=Uri.parse(url);
-        if(uri!=null){
-          Uri.Builder builder=new Uri.Builder();
-          builder.scheme(uri.getScheme());
-          builder.authority(uri.getAuthority());
-          builder.path(uri.getPath());
-          pageName=builder.toString();
-        }
-      } catch (Exception e) {
-      }
-    }
-    return pageName;
-  }
-
-  private String assembleFilePath(Uri uri) {
-    if(uri!=null && uri.getPath()!=null){
-      return uri.getPath().replaceFirst("/","");
-    }
-    return "";
-  }
-
-  public void reloadPage(boolean reloadThis) {
-
-    WXSDKEngine.reload();
-
-    if (reloadThis) {
-      if (mContext != null)  {
-        Intent intent = new Intent();
-        intent.setAction(ACTION_INSTANCE_RELOAD);
-        intent.putExtra("url", mBundleUrl);
-        mContext.sendBroadcast(intent);
-      }
-      // mRendered = false;
-      //    destroy();
-      // renderInternal(mPackage, mTemplate, mOptions, mJsonInitData, mFlag);
-      // refreshInstance("{}");
-    } else {
-      IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
-      if (adapter != null) {
-        boolean degrade = Boolean.parseBoolean(adapter
-                .getConfig("android_weex_ext_config",
-                        "degrade_to_h5_if_not_reload",
-                        "true"));
-        WXLogUtils.e("degrade : " + degrade);
-        if(degrade) {
-          onJSException(String.valueOf(WX_ERR_RELOAD_PAGE.getErrorCode()),"Do not reloadPage", "Do not reloadPage degradeToH5");
-          WXLogUtils.e("Do not reloadPage degradeToH5");
-        }
-      }
-    }
-  }
-
-  /**
-   * Refresh instance asynchronously.
-   * @param data the new data
-   */
-  public void refreshInstance(Map<String, Object> data) {
-    if (data == null) {
-      return;
-    }
-    refreshInstance(WXJsonUtils.fromObjectToJSONString(data));
-  }
-
-  /**
-   * Refresh instance asynchronously.
-   * @param jsonData the new data
-   */
-  public void refreshInstance(String jsonData) {
-    if (jsonData == null) {
-      return;
-    }
-    mRefreshStartTime = System.currentTimeMillis();
-    //cancel last refresh message
-    if (mLastRefreshData != null) {
-      mLastRefreshData.isDirty = true;
-    }
-
-    mLastRefreshData = new WXRefreshData(jsonData, false);
-
-    WXSDKManager.getInstance().refreshInstance(mInstanceId, mLastRefreshData);
-  }
-
-  public WXRenderStrategy getRenderStrategy() {
-    return mRenderStrategy;
-  }
-
-  public Context getUIContext() {
-    return mContext;
-  }
-
-  public String getInstanceId() {
-    return mInstanceId;
-  }
-
-  public Context getContext() {
-    return mContext;
-  }
-
-  public int getWeexHeight() {
-    return mRenderContainer == null ? 0: mRenderContainer.getHeight();
-  }
-
-  public int getWeexWidth() {
-    return mRenderContainer == null ? 0: mRenderContainer.getWidth();
-  }
-
-
-  public IWXImgLoaderAdapter getImgLoaderAdapter() {
-    return WXSDKManager.getInstance().getIWXImgLoaderAdapter();
-  }
-
-  public IDrawableLoader getDrawableLoader() {
-    return WXSDKManager.getInstance().getDrawableLoader();
-  }
-
-  public URIAdapter getURIAdapter(){
-    return WXSDKManager.getInstance().getURIAdapter();
-  }
-
-  public Uri rewriteUri(Uri uri,String type){
-    return getURIAdapter().rewrite(this,type,uri);
-  }
-
-  public IWXHttpAdapter getWXHttpAdapter() {
-    return WXSDKManager.getInstance().getIWXHttpAdapter();
-  }
-
-  public IWXStatisticsListener getWXStatisticsListener() {
-    return mStatisticsListener;
-  }
-
-  public @Nullable
-  IWebSocketAdapter getWXWebSocketAdapter() {
-    return WXSDKManager.getInstance().getIWXWebSocketAdapter();
-  }
-
-  @Deprecated
-  public void reloadImages() {
-    if (mScrollView == null) {
-      return;
-    }
-  }
-
-
-  public boolean isPreRenderMode() {
-    return this.isPreRenderMode;
-  }
-
-  public void setPreRenderMode(final boolean isPreRenderMode) {
-    WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
-      @Override
-      public void run() {
-        WXSDKInstance.this.isPreRenderMode = isPreRenderMode;
-      }
-    },0);
-  }
-
-  public void setContext(@NonNull Context context) {
-    this.mContext = context;
-  }
-
-  /********************************
-   * begin register listener
-   ********************************************************/
-  public void registerRenderListener(IWXRenderListener listener) {
-    mRenderListener = listener;
-  }
-
-  @Deprecated
-  public void registerActivityStateListener(IWXActivityStateListener listener) {
-
-  }
-
-  public void registerStatisticsListener(IWXStatisticsListener listener) {
-    mStatisticsListener = listener;
-  }
-
-  /**set render start time*/
-  public void setRenderStartTime(long renderStartTime) {
-    this.mRenderStartTime = renderStartTime;
-  }
-
-  /********************************
-   * end register listener
-   ********************************************************/
-
-
-  /********************************
-   *  begin hook Activity life cycle callback
-   ********************************************************/
-
-  @Override
-  public void onActivityCreate() {
-
-    // module listen Activity onActivityCreate
-    WXModuleManager.onActivityCreate(getInstanceId());
-
-    if(mRootComp != null) {
-      mRootComp.onActivityCreate();
-    }else{
-        if (WXEnvironment.isApkDebugable()){
-            WXLogUtils.w("Warning :Component tree has not build completely,onActivityCreate can not be call!");
-        }
-    }
-
-    mGlobalEventReceiver=new WXGlobalEventReceiver(this);
-    try {
-      getContext().registerReceiver(mGlobalEventReceiver, new IntentFilter(WXGlobalEventReceiver.EVENT_ACTION));
-    } catch (Throwable e) {
-      // Huawei may throw a exception if register more than 500 BroadcastReceivers
-      WXLogUtils.e(e.getMessage());
-      mGlobalEventReceiver = null;
-    }
-
-  }
-
-  @Override
-  public void onActivityStart() {
-
-    // module listen Activity onActivityCreate
-    WXModuleManager.onActivityStart(getInstanceId());
-    if(mRootComp != null) {
-      mRootComp.onActivityStart();
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!");
-
-        }
-    }
-
-  }
-
-  public boolean onCreateOptionsMenu(Menu menu) {
-
-    WXModuleManager.onCreateOptionsMenu(getInstanceId(),menu);
-    if(mRootComp != null) {
-      mRootComp.onCreateOptionsMenu(menu);
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!");
-
-        }
-    }
-    return true;
-  }
-
-  @Override
-  public void onActivityPause() {
-    onViewDisappear();
-    if(!isCommit){
-      if(mUseScroller){
-        mWXPerformance.useScroller=1;
-      }
-      mWXPerformance.maxDeepViewLayer=getMaxDeepLayer();
-      mWXPerformance.wxDims = mwxDims;
-      mWXPerformance.measureTimes = measureTimes;
-      if (mUserTrackAdapter != null) {
-        mUserTrackAdapter.commit(mContext, null, IWXUserTrackAdapter.LOAD, mWXPerformance, getUserTrackParams());
-      }
-      isCommit=true;
-    }
-    // module listen Activity onActivityPause
-    WXModuleManager.onActivityPause(getInstanceId());
-    if(mRootComp != null) {
-      mRootComp.onActivityPause();
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely,onActivityPause can not be call!");
-        }
-    }
-
-    if (!mCurrentGround) {
-      WXLogUtils.i("Application to be in the backround");
-      Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION);
-      intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.PAUSE_EVENT);
-      intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId());
-      /**
-       *  Fix NPE just like {@link #onActivityResume()}
-       */
-      if (null != mContext){
-        mContext.sendBroadcast(intent);
-      }else {
-        try {
-          WXEnvironment.getApplication().sendBroadcast(intent);
-        } catch (Exception e){
-          WXLogUtils.e("weex",e);
-        }
-      }
-      this.mCurrentGround = true;
-    }
-
-    //component appear
-    if((WXEnvironment.isApkDebugable() || WXEnvironment.isPerf()) && mApmForInstance != null){
-        WXLogUtils.e("PerformanceData " + mApmForInstance.toPerfString());
-    }
-  }
-
-
-  @Override
-  public void onActivityResume() {
-
-    // notify onActivityResume callback to module
-    WXModuleManager.onActivityResume(getInstanceId());
-
-    if(mRootComp != null) {
-      mRootComp.onActivityResume();
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely, onActivityResume can not be call!");
-        }
-    }
-
-    if (mCurrentGround) {
-      WXLogUtils.i("Application  to be in the foreground");
-      Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION);
-      intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.RESUME_EVENT);
-      intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId());
-      //todo tmp solution for gray version
-      if (null != mContext){
-        mContext.sendBroadcast(intent);
-      }else {
-        WXEnvironment.getApplication().sendBroadcast(intent);
-      }
-      this.mCurrentGround = false;
-    }
-
-    onViewAppear();
-  }
-
-  @Override
-  public void onActivityStop() {
-
-    // notify onActivityResume callback to module
-    WXModuleManager.onActivityStop(getInstanceId());
-
-    if(mRootComp != null) {
-      mRootComp.onActivityStop();
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely, onActivityStop can not be call!");
-        }
-    }
-
-  }
-
-  @Override
-  public void onActivityDestroy() {
-    WXModuleManager.onActivityDestroy(getInstanceId());
-
-    if(mRootComp != null) {
-      mRootComp.onActivityDestroy();
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely, onActivityDestroy can not be call!");
-        }
-    }
-    this.mTimeCalculator.println();
-    destroy();
-  }
-
-  @Override
-  public boolean onActivityBack() {
-
-    WXModuleManager.onActivityBack(getInstanceId());
-
-    if(mRootComp != null) {
-      return mRootComp.onActivityBack();
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely, onActivityBack can not be call!");
-        }
-    }
-
-    return false;
-  }
-
-  public boolean onSupportNavigateUp() {
-    if (mWXActionbarHandlers != null) {
-      for (ActionBarHandler handler : mWXActionbarHandlers) {
-        if (handler.onSupportNavigateUp()) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  public boolean onBackPressed() {
-    if(mWXBackPressedHandlers != null) {
-      for (OnBackPressedHandler handler : mWXBackPressedHandlers) {
-        if(handler.onBackPressed()) {
-          return true;
-        }
-      }
-    }
-
-    WXComponent comp = getRootComponent();
-    if(comp != null) {
-      WXEvent events= comp.getEvents();
-      boolean hasNativeBackHook = events.contains(Constants.Event.NATIVE_BACK);
-      if (hasNativeBackHook) {
-        EventResult result = comp.fireEventWait(Constants.Event.NATIVE_BACK, null);
-        if (WXUtils.getBoolean(result.getResult(), false)) {
-          return true;
-        }
-      }
-
-      boolean hasBackPressed = events.contains(Constants.Event.CLICKBACKITEM);
-      if (hasBackPressed) {
-        fireEvent(comp.getRef(), Constants.Event.CLICKBACKITEM,null, null);
-      }
-      return hasBackPressed;
-    }
-    return false;
-  }
-
-  public void onActivityResult(int requestCode, int resultCode, Intent data){
-    WXModuleManager.onActivityResult(getInstanceId(),requestCode,resultCode,data);
-
-    if(mRootComp != null) {
-      mRootComp.onActivityResult(requestCode,resultCode,data);
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("Warning :Component tree has not build completely, onActivityResult can not be call!");
-        }
-    }
-
-
-    if (mWXOnActivityResultHandlers != null && !mWXOnActivityResultHandlers.isEmpty()) {
-      for (OnActivityResultHandler onActivityResultHandler : mWXOnActivityResultHandlers) {
-        if (onActivityResultHandler.onActivityResult(requestCode, resultCode, data)) {
-          break;
-        }
-      }
-    }
-
-  }
-
-
-  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
-
-    WXModuleManager.onRequestPermissionsResult(getInstanceId(),requestCode,permissions,grantResults);
-
-    if(mRootComp != null) {
-       mRootComp.onRequestPermissionsResult(requestCode,permissions,grantResults);
-    }else{
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w(
-                "Warning :Component tree has not build completely, onRequestPermissionsResult can not be call!");
-        }
-    }
-  }
-
-  /********************************
-   *  end hook Activity life cycle callback
-   ********************************************************/
-
-  public void onViewDisappear(){
-    isViewDisAppear = false;
-    mApmForInstance.onDisAppear();
-    WXComponent comp = getRootComponent();
-    if(comp != null) {
-      fireEvent(comp.getRef(), Constants.Event.VIEWDISAPPEAR, null, null);
-      //call disappear of nested instances
-      for(OnInstanceVisibleListener instance:mVisibleListeners){
-        instance.onDisappear();
-      }
-    }
-  }
-
-  public boolean isViewDisAppear(){
-    return isViewDisAppear;
-  }
-
-  public void onViewAppear(){
-    isViewDisAppear = true;
-    mApmForInstance.onAppear();
-    WXComponent comp = getRootComponent();
-    if(comp != null) {
-      fireEvent( comp.getRef(), Constants.Event.VIEWAPPEAR,null, null);
-      for(OnInstanceVisibleListener instance:mVisibleListeners){
-        instance.onAppear();
-      }
-    }
-  }
-
-
-  public void onCreateFinish() {
-    if(mHasCreateFinish){
-      return;
-    }
-    if (mContext != null) {
-      onViewAppear();
-      View wxView= mRenderContainer;
-      if(mRenderListener != null) {
-        mRenderListener.onViewCreated(WXSDKInstance.this, wxView);
-      }
-      if (mStatisticsListener != null) {
-        mStatisticsListener.onFirstView();
-      }
-    }
-  }
-
-  /**
-   * call back when update finish
-   */
-  public void onUpdateFinish() {
-    if (WXEnvironment.isApkDebugable()){
-      WXLogUtils.d("Instance onUpdateSuccess");
-    }
-  }
-
-
-  public void runOnUiThread(Runnable action) {
-    WXSDKManager.getInstance().postOnUiThread(action, 0);
-  }
-
-  public void onRenderSuccess(final int width, final int height) {
-    isRenderSuccess = true;
-    if (!isNewFsEnd){
-      getApmForInstance().arriveNewFsRenderTime();
-    }
-
-    long time = System.currentTimeMillis() - mRenderStartTime;
-    long[] renderFinishTime = WXBridgeManager.getInstance().getRenderFinishTime(getInstanceId());
-
-    mWXPerformance.callBridgeTime = renderFinishTime[0];
-    mWXPerformance.cssLayoutTime = renderFinishTime[1];
-    mWXPerformance.parseJsonTime = renderFinishTime[2];
-
-    mWXPerformance.totalTime = time;
-    if(mWXPerformance.screenRenderTime<0.001){
-      mWXPerformance.screenRenderTime =  time;
-    }
-
-    if (mRenderListener != null && mContext != null) {
-      mRenderListener.onRenderSuccess(WXSDKInstance.this, width, height);
-      if (mUserTrackAdapter != null) {
-        WXPerformance performance=new WXPerformance(mInstanceId);
-        performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode();
-        performance.args=getBundleUrl();
-        mUserTrackAdapter.commit(mContext,null,IWXUserTrackAdapter.JS_BRIDGE,performance,getUserTrackParams());
-      }
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d(WXLogUtils.WEEX_PERF_TAG, mWXPerformance.toString());
-      }
-    }
-    if(WXEnvironment.isPerf()){
-      WXLogUtils.e("weex_perf",mWXPerformance.getPerfData());
-    }
-  }
-
-  public void onRefreshSuccess(final int width, final int height) {
-    if (mRenderListener != null && mContext != null) {
-      mRenderListener.onRefreshSuccess(WXSDKInstance.this, width, height);
-    }
-  }
-
-  public void onChangeElement(WXComponent component, boolean isOutOfScreen) {
-
-    if (isDestroy()  || null == mRenderContainer || mWXPerformance == null ){
-      return;
-    }
-    if (null == component || component.isIgnoreInteraction){
-        return;
-    }
-
-    if (mRenderContainer.hasConsumeEvent()) {
-      return;
-    }
-
-    long lastElementChangeTime = System.currentTimeMillis();
-
-    long lazyLoadTime;
-
-    if (mHasCreateFinish){
-      lazyLoadTime = lastElementChangeTime - mWXPerformance.renderTimeOrigin;
-      if (lazyLoadTime > 8000) {
-        //force record detail performance data
-        return;
-      }
-    }
-
-    if (component.mIsAddElementToTree) {
-      getWXPerformance().localInteractionViewAddCount++;
-      if (!isOutOfScreen)
-        getWXPerformance().interactionViewAddLimitCount++;
-      component.mIsAddElementToTree = false;
-    }
-
-    if (!isOutOfScreen) {
-      mApmForInstance.arriveInteraction(component);
-    }
-  }
-
-  public void onRenderError(final String errCode, final String msg) {
-    WXStateRecord.getInstance().recordException(getInstanceId(),"onRenderError,"+errCode+","+msg);
-    if (mRenderListener != null && mContext != null) {
-      WXLogUtils.e("onRenderError "+errCode +","+msg);
-      runOnUiThread(new Runnable() {
-
-        @Override
-        public void run() {
-          if (mRenderListener != null && mContext != null) {
-            mRenderListener.onException(WXSDKInstance.this, errCode, msg);
-          }
-        }
-      });
-    }
-  }
-
-  public void onJSException(final String errCode, final String function, final String exception) {
-    WXStateRecord.getInstance().recordException(getInstanceId(),"onJSException,"+errCode+","+function+"|"+exception);
-    hasException = true;
-    if (mRenderListener != null && mContext != null) {
-      WXLogUtils.e("onJSException "+errCode +","+exception);
-      runOnUiThread(new Runnable() {
-
-        @Override
-        public void run() {
-          if (mRenderListener != null && mContext != null) {
-            StringBuilder builder = new StringBuilder();
-            builder.append(function);
-            builder.append(exception);
-            mRenderListener.onException(WXSDKInstance.this, errCode, builder.toString());
-          }
-        }
-      });
-    }
-  }
-
-
-  @Override
-  public final void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int
-          oldTop, int oldRight, int oldBottom) {
-    if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
-      onLayoutChange(v);
-    }
-  }
-
-  /**
-   * Subclass should override this method to get notifications of layout change of GodView.
-   * @param godView the godView.
-   */
-  public void onLayoutChange(View godView) {
-
-  }
-
-  private boolean mCreateInstance =true;
-  public void firstScreenCreateInstanceTime(long time) {
-    if(mCreateInstance) {
-      mWXPerformance.firstScreenJSFExecuteTime = time -mRenderStartTime;
-      mCreateInstance =false;
-    }
-  }
-
-  public void callJsTime(final long time){
-    if (!mEnd){
-      mWXPerformance.fsCallJsTotalTime+=time;
-      mWXPerformance.fsCallJsTotalNum++;
-    }
-  }
-
-  public void onComponentCreate(WXComponent component,long createTime) {
-      mWXPerformance.mActionAddElementCount++;
-      mWXPerformance.mActionAddElementSumTime += createTime;
-      if (!mEnd){
-        mWXPerformance.fsComponentCreateTime+=createTime;
-        mWXPerformance.fsComponentCount++;
-      }
-      mWXPerformance.componentCount++;
-      mWXPerformance.componentCreateTime+=createTime;
-  }
-
-  public void callActionAddElementTime(long time) {
-      mWXPerformance.mActionAddElementSumTime += time;
-  }
-
-  public void onOldFsRenderTimeLogic(){
-      if (mEnd){
-        return;
-      }
-      mEnd = true;
-      if (mStatisticsListener != null && mContext != null) {
-        runOnUiThread(new Runnable() {
-        @Override
-        public void run() {
-            if (mStatisticsListener != null && mContext != null) {
-              Trace.beginSection("onFirstScreen");
-              mStatisticsListener.onFirstScreen();
-              Trace.endSection();
-            }
-          }
-        });
-      }
-      mApmForInstance.arriveFSRenderTime();
-      mWXPerformance.fsRenderTime = System.currentTimeMillis();
-      mWXPerformance.screenRenderTime = System.currentTimeMillis() - mRenderStartTime;
-  }
-
-  public WXSDKInstance getParentInstance() {
-    return mParentInstance;
-  }
-
-  public void setParentInstance(WXSDKInstance mParentInstance) {
-    this.mParentInstance = mParentInstance;
-  }
-
-  private void destroyView(View rootView) {
-    try {
-      if (rootView instanceof ViewGroup) {
-        ViewGroup cViewGroup = ((ViewGroup) rootView);
-        for (int index = 0; index < cViewGroup.getChildCount(); index++) {
-          destroyView(cViewGroup.getChildAt(index));
-        }
-
-        cViewGroup.removeViews(0, ((ViewGroup) rootView).getChildCount());
-        // Ensure that the viewgroup's status to be normal
-        WXReflectionUtils.setValue(rootView, "mChildrenCount", 0);
-
-      }
-      if(rootView instanceof Destroyable){
-        ((Destroyable)rootView).destroy();
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("WXSDKInstance destroyView Exception: ", e);
-    }
-  }
-
-  public synchronized void destroy() {
-    if(!isDestroy()) {
-      if(mParentInstance != null){
-         mParentInstance = null;
-      }
-      mApmForInstance.onEnd();
-
-
-      if(mRendered) {
-        WXSDKManager.getInstance().destroyInstance(mInstanceId);
-      }
-
-      try {
-        if (mGlobalEventReceiver != null) {
-          getContext().unregisterReceiver(mGlobalEventReceiver);
-          mGlobalEventReceiver = null;
-        }
-      }catch (IllegalArgumentException e){
-        WXLogUtils.w(WXLogUtils.getStackTrace(e));
-      }
-
-      if (mRootComp != null) {
-        mRootComp.destroy();
-        mRootComp = null;
-      }
-
-      if(mRenderContainer != null){
-        destroyView(mRenderContainer);
-      }
-
-
-      if (mGlobalEvents != null) {
-        mGlobalEvents.clear();
-      }
-
-      if (mComponentObserver != null) {
-        mComponentObserver = null;
-      }
-
-      if (mLayerOverFlowListeners != null) {
-        mLayerOverFlowListeners.clear();
-      }
-
-      if(mWXOnActivityResultHandlers != null && !mWXOnActivityResultHandlers.isEmpty()) {
-        mWXOnActivityResultHandlers.clear();
-      }
-
-      if(mWXBackPressedHandlers != null && !mWXBackPressedHandlers.isEmpty()) {
-        mWXBackPressedHandlers.clear();
-      }
-
-      if(mWXActionbarHandlers != null && !mWXActionbarHandlers.isEmpty()) {
-        mWXActionbarHandlers.clear();
-      }
-
-      getFlatUIContext().destroy();
-      mFlatGUIContext = null;
-      mInstanceOnFireEventInterceptorList = null;
-      mWXScrollListeners = null;
-      mWXActionbarHandlers = null;
-      mWXBackPressedHandlers = null;
-      mRenderContainer = null;
-      mNestedInstanceInterceptor = null;
-      mUserTrackAdapter = null;
-      mScrollView = null;
-      mContext = null;
-      mRenderListener = null;
-      isDestroy = true;
-      mStatisticsListener = null;
-      if(responseHeaders != null){
-        responseHeaders.clear();
-      }
-      if(templateRef != null){
-        templateRef = null;
-      }
-      if (null != mContentBoxMeasurements) {
-        mContentBoxMeasurements.clear();
-      }
-      mWXPerformance.afterInstanceDestroy(mInstanceId);
-
-      WXBridgeManager.getInstance().post(new Runnable() {
-        @Override
-        public void run() {
-          WXBridgeManager.getInstance().onInstanceClose(getInstanceId());
-          inactiveAddElementAction.clear();
-        }
-      });
-
-      //when report error in @WXExceptionUtils
-      // instance may had destroy and remove,
-      // so we delay remove from allInstanceMap
-      WXBridgeManager.getInstance().postDelay(new Runnable() {
-        @Override
-        public void run() {
-          WXSDKManager.getInstance().getAllInstanceMap().remove(mInstanceId);
-        }
-      },1000);
-    }
-  }
-
-  public boolean isDestroy(){
-    return isDestroy;
-  }
-
-  /**
-   * @return If you use render () the return value may be empty
-   */
-  public @Nullable String getBundleUrl() {
-    return mBundleUrl;
-  }
-
-  public View getRootView() {
-    if (mRootComp == null)
-      return null;
-    return mRootComp.getRealView();
-  }
-
-  public View getContainerView() {
-    return mRenderContainer;
-  }
-
-  @Deprecated
-  public void setBundleUrl(String url){
-    mBundleUrl = url;
-    if(WXSDKManager.getInstance().getValidateProcessor()!=null) {
-      mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl);
-    }
-  }
-
-  public void onRootCreated(WXComponent root) {
-    this.mRootComp = root;
-    this.mRootComp.mDeepInComponentTree =1;
-    mRenderContainer.addView(root.getHostView());
-
-
-    setSize(mRenderContainer.getWidth(),mRenderContainer.getHeight());
-  }
-
-  /**
-   * Move fixed view to container ,except it's already moved.
-   * @param fixedChild
-   */
-  public void moveFixedView(View fixedChild){
-    if(mRenderContainer != null) {
-      ViewGroup parent;
-      if((parent = (ViewGroup) fixedChild.getParent()) != null){
-        if (parent != mRenderContainer) {
-          parent.removeView(fixedChild);
-          mRenderContainer.addView(fixedChild);
-        }
-      }else{
-        mRenderContainer.addView(fixedChild);
-      }
-    }
-  }
-
-  public void removeFixedView(View fixedChild){
-    if(mRenderContainer != null) {
-      mRenderContainer.removeView(fixedChild);
-    }
-  }
-
-  public int getRenderContainerPaddingLeft() {
-    if(mRenderContainer != null) {
-      return mRenderContainer.getPaddingLeft();
-    }
-    return 0;
-  }
-
-  public int getRenderContainerPaddingRight() {
-    if(mRenderContainer != null) {
-      return mRenderContainer.getPaddingRight();
-    }
-    return 0;
-  }
-
-  public int getRenderContainerPaddingTop() {
-    if(mRenderContainer != null) {
-      return mRenderContainer.getPaddingTop();
-    }
-    return 0;
-  }
-
-  public synchronized List<OnWXScrollListener> getWXScrollListeners() {
-    return mWXScrollListeners;
-  }
-
-  public synchronized void registerOnWXScrollListener(OnWXScrollListener wxScrollListener) {
-    if(mWXScrollListeners==null){
-      mWXScrollListeners=new ArrayList<>();
-    }
-    mWXScrollListeners.add(wxScrollListener);
-  }
-
-  public synchronized void registerActionbarHandler(ActionBarHandler actionBarHandler) {
-    if(actionBarHandler == null) {
-      return;
-    }
-    if(mWXActionbarHandlers == null) {
-      mWXActionbarHandlers = new ArrayList<>();
-    }
-
-    mWXActionbarHandlers.add(actionBarHandler);
-  }
-
-  public synchronized void unRegisterActionbarHandler(ActionBarHandler actionBarHandler) {
-    if(mWXActionbarHandlers != null && actionBarHandler != null) {
-      mWXActionbarHandlers.remove(actionBarHandler);
-    }
-  }
-
-  public synchronized void unRegisterOnActivityResultHandler(OnActivityResultHandler onActivityResultHandler) {
-    if(mWXOnActivityResultHandlers != null && onActivityResultHandler != null) {
-      mWXOnActivityResultHandlers.remove(onActivityResultHandler);
-    }
-  }
-
-  public synchronized void registerOnActivityResultHandler(OnActivityResultHandler onActivityResultHandler) {
-    if(onActivityResultHandler == null) {
-      return;
-    }
-
-    if(mWXOnActivityResultHandlers == null) {
-      mWXOnActivityResultHandlers = new ArrayList<>();
-    }
-    mWXOnActivityResultHandlers.add(onActivityResultHandler);
-  }
-
-
-  public synchronized void registerBackPressedHandler(OnBackPressedHandler backPressedHandler) {
-    if(backPressedHandler == null) {
-      return;
-    }
-
-    if(mWXBackPressedHandlers == null) {
-      mWXBackPressedHandlers = new ArrayList<>();
-    }
-
-    mWXBackPressedHandlers.add(backPressedHandler);
-  }
-
-  public synchronized void unRegisterBackPressedHandler(OnBackPressedHandler backPressedHandler) {
-    if(mWXBackPressedHandlers != null && backPressedHandler != null) {
-      mWXBackPressedHandlers.remove(backPressedHandler);
-    }
-  }
-
-  static int sScreenHeight = -1;
-  public void setSize(int width, int height) {
-    if (width > 0 && height > 0 & !isDestroy && mRendered && mRenderContainer != null) {
-        if (sScreenHeight < 0){
-            sScreenHeight = WXViewUtils.getScreenHeight(getContext());
-        }
-        if (sScreenHeight>0){
-            double screenRatio = (double)height/(double)sScreenHeight *100;
-            if(screenRatio>100){
-              screenRatio =100;
-            }
-            getApmForInstance().addStats(WXInstanceApm.KEY_PAGE_STATS_BODY_RATIO,screenRatio);
-        }
-      ViewGroup.LayoutParams layoutParams = mRenderContainer.getLayoutParams();
-      if (layoutParams != null) {
-        final float realWidth = width;
-        final float realHeight = height;
-        if (mRenderContainer.getWidth() != width || mRenderContainer.getHeight() != height) {
-          layoutParams.width = width;
-          layoutParams.height = height;
-          mRenderContainer.setLayoutParams(layoutParams);
-        }
-
-        if (mRootComp != null && layoutParams != null) {
-          final boolean isWidthWrapContent = layoutParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
-          final boolean isHeightWrapContent = layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT;
-
-          WXBridgeManager.getInstance().post(new Runnable() {
-            @Override
-            public void run() {
-              WXBridgeManager.getInstance().setDefaultRootSize(getInstanceId(), realWidth, realHeight, isWidthWrapContent,
-                      isHeightWrapContent);
-            }
-          });
-        }
-      }
-    }
-  }
-
-  /*Global Event*/
-  private HashMap<String, List<String>> mGlobalEvents = new HashMap<>();
-
-  public void fireGlobalEventCallback(String eventName, Map<String,Object> params){
-    List<String> callbacks=mGlobalEvents.get(eventName);
-    if(callbacks!=null){
-      for(String callback:callbacks){
-        WXSDKManager.getInstance().callback(mInstanceId,callback,params,true);
-      }
-    }
-  }
-
-  /**
-   * Fire event callback on a element.
-   * @param elementRef
-   * @param type
-   * @param data
-   * @param domChanges
-   */
-  public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges, List<Object> eventArgs){
-    fireEvent(elementRef, type, data, domChanges, eventArgs, null);
-  }
-
-  public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges, List<Object> eventArgs, EventResult callback) {
-    onInterceptInstanceEvent(getInstanceId(), elementRef, type, data, domChanges);
-    if (null != mWXPerformance && mWXPerformance.fsCallEventTotalNum<Integer.MAX_VALUE){
-      mWXPerformance.fsCallEventTotalNum++;
-    }
-    mApmForInstance.updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_EVENT_NUM,1);
-    WXBridgeManager.getInstance().fireEventOnNode(getInstanceId(),elementRef,type,data,domChanges, eventArgs, callback);
-  }
-
-
-  /**
-   * Fire event callback on a element.
-   * @param elementRef
-   * @param type
-   * @param data
-   * @param domChanges
-   */
-  public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges){
-    fireEvent(elementRef, type, data, domChanges, null);
-  }
-
-  public void fireEvent(String elementRef,final String type, final Map<String, Object> data){
-    fireEvent(elementRef,type,data,null);
-  }
-
-  public void fireEvent(String ref, String type){
-    fireEvent(ref,type,new HashMap<String, Object>());
-  }
-
-  protected void addEventListener(String eventName, String callback) {
-    if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) {
-      return;
-    }
-    List<String> callbacks = mGlobalEvents.get(eventName);
-    if (callbacks == null) {
-      callbacks = new ArrayList<>();
-      mGlobalEvents.put(eventName, callbacks);
-    }
-    callbacks.add(callback);
-  }
-  protected void removeEventListener(String eventName, String callback) {
-    if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) {
-      return;
-    }
-    List<String> callbacks = mGlobalEvents.get(eventName);
-    if (callbacks != null) {
-      callbacks.remove(callback);
-    }
-  }
-
-  protected void removeEventListener(String eventName) {
-    if (TextUtils.isEmpty(eventName)) {
-      return;
-    }
-    mGlobalEvents.remove(eventName);
-  }
-
-  /**
-   * Notifies WEEX that this event has occurred
-   * @param eventName WEEX register event
-   * @param module Events occur in this Module
-   * @param params The parameters to be notified to WEEX are required
-   */
-  public void fireModuleEvent(String eventName, WXModule module,Map<String, Object> params) {
-    if (TextUtils.isEmpty(eventName) || module == null) {
-      return;
-    }
-
-    Map<String, Object> event = new HashMap<>();
-    event.put("type", eventName);
-    event.put("module", module.getModuleName());
-    event.put("data", params);
-
-    List<String> callbacks = module.getEventCallbacks(eventName);
-    if (callbacks != null) {
-      for (String callback : callbacks) {
-        SimpleJSCallback jsCallback = new SimpleJSCallback(mInstanceId, callback);
-        if (module.isOnce(callback)) {
-          jsCallback.invoke(event);
-        } else {
-          jsCallback.invokeAndKeepAlive(event);
-        }
-      }
-    }
-  }
-
-  /**
-   * Check whether the current module registered the event
-   * @param eventName EventName register in weex
-   * @param module Events occur in this Module
-   * @return  register->true
-   */
-  public boolean checkModuleEventRegistered(String eventName,WXModule module) {
-    if (module != null) {
-      List<String> events = module.getEventCallbacks(eventName);
-      if (events != null && events.size() > 0) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public WXPerformance getWXPerformance(){
-    return mWXPerformance;
-  }
-
-  public WXInstanceApm getApmForInstance() {
-    return mApmForInstance;
-  }
-
-  public Map<String, Serializable> getUserTrackParams() {
-    return mUserTrackParams;
-  }
-
-  public void addUserTrackParameter(String key,Serializable value){
-    if(this.mUserTrackParams == null){
-      this.mUserTrackParams = new ConcurrentHashMap<>();
-    }
-    mUserTrackParams.put(key,value);
-  }
-
-  public void clearUserTrackParameters(){
-    if(this.mUserTrackParams != null){
-      this.mUserTrackParams.clear();
-    }
-  }
-
-  public void removeUserTrackParameter(String key){
-    if(this.mUserTrackParams != null){
-      this.mUserTrackParams.remove(key);
-    }
-  }
-
-  public int getMaxDeepLayer() {
-    return mMaxDeepLayer;
-  }
-
-  public void setMaxDeepLayer(int maxDeepLayer) {
-    mMaxDeepLayer = maxDeepLayer;
-    mApmForInstance.updateMaxStats(WXInstanceApm.KEY_PAGE_STATS_MAX_DEEP_VIEW,maxDeepLayer);
-  }
-
-  public void setMaxDomDeep(int maxDomDeep){
-    mApmForInstance.updateMaxStats(WXInstanceApm.KEY_PAGE_STATS_MAX_DEEP_DOM,maxDomDeep);
-    if (null == mWXPerformance){
-      return;
-    }
-    if (mWXPerformance.maxDeepVDomLayer <= maxDomDeep){
-      mWXPerformance.maxDeepVDomLayer = maxDomDeep;
-    }
-  }
-
-  public void onHttpStart(){
-    if (!mEnd){
-      mWXPerformance.fsRequestNum++;
-    }
-  }
-
-  /**
-   * return md5, and bytes length
-   * */
-  public String getTemplateInfo() {
-    String template = getTemplate();
-    if(template == null){
-      return " template md5 null ,httpHeader:" + JSONObject.toJSONString(responseHeaders);
-    }
-    if(TextUtils.isEmpty(template)){
-      return " template md5  length 0 ,httpHeader" + JSONObject.toJSONString(responseHeaders);
-    }
-    try {
-      byte[] bts = template.getBytes("UTF-8");
-      String sourceMD5 = WXFileUtils.md5(bts);
-      String sourceBase64MD5 = WXFileUtils.base64Md5(bts);
-      ArrayList<String> sourceMD5List = new ArrayList<>();
-      ArrayList<String> sourceBase64MD5List = new ArrayList<>();
-      sourceMD5List.add(sourceMD5);
-      sourceBase64MD5List.add(sourceBase64MD5);
-      responseHeaders.put("templateSourceMD5", sourceMD5List);
-      responseHeaders.put(SOURCE_TEMPLATE_BASE64_MD5, sourceBase64MD5List);
-      return " template md5 " + sourceMD5 + " length " +   bts.length
-              + " base64 md5 " + sourceBase64MD5
-              + " response header " + JSONObject.toJSONString(responseHeaders);
-    } catch (Exception e) {
-      return "template md5 getBytes error";
-    }
-
-  }
-
-  /**
-   * check template header md5 match with header  content-md5
-   * */
-  public boolean isContentMd5Match(){
-    if(responseHeaders == null){
-      return true;
-    }
-    List<String> contentMD5s = responseHeaders.get("Content-Md5");
-    if(contentMD5s == null){
-      contentMD5s  = responseHeaders.get("content-md5");
-    }
-    if(contentMD5s == null || contentMD5s.size() <= 0){
-      return true;
-    }
-    String md5 = contentMD5s.get(0);
-
-    List<String> sourceBase64Md5 = responseHeaders.get(SOURCE_TEMPLATE_BASE64_MD5);
-    if(sourceBase64Md5 == null){
-      getTemplateInfo();
-      sourceBase64Md5 = responseHeaders.get(SOURCE_TEMPLATE_BASE64_MD5);
-    }
-    if(sourceBase64Md5 == null || sourceBase64Md5.size() == 0){
-      return  true;
-    }
-    return  md5.equals(sourceBase64Md5.get(0));
-  }
-
-  public String getTemplate() {
-    if(templateRef == null){
-      return  null;
-    }
-    return templateRef.get();
-  }
-
-  public void setTemplate(String template) {
-    this.templateRef = new WeakReference<String>(template);
-  }
-
-  public interface NestedInstanceInterceptor {
-    void onCreateNestInstance(WXSDKInstance instance, NestedContainer container);
-  }
-
-  public void OnVSync() {
-    boolean forceLayout = WXBridgeManager.getInstance().notifyLayout(getInstanceId());
-    if(forceLayout) {
-      WXBridgeManager.getInstance().post(new Runnable() {
-        @Override
-        public void run() {
-          WXBridgeManager.getInstance().forceLayout(getInstanceId());
-        }
-      });
-    }
-  }
-
-  public void addContentBoxMeasurement(long renderObjectPtr, ContentBoxMeasurement contentBoxMeasurement) {
-    mContentBoxMeasurements.put(renderObjectPtr, contentBoxMeasurement);
-  }
-
-  public ContentBoxMeasurement getContentBoxMeasurement(long renderObjectPtr) {
-    return mContentBoxMeasurements.get(renderObjectPtr);
-  }
-
-
-  private void onInterceptInstanceEvent(String instanceId, String elementRef, String type, Map<String, Object> data, Map<String, Object> domChanges) {
-    if(this.mInstanceOnFireEventInterceptorList == null){
-      return;
-    }
-    for(InstanceOnFireEventInterceptor instanceOnFireEventInterceptor : this.mInstanceOnFireEventInterceptorList){
-      instanceOnFireEventInterceptor.onInterceptFireEvent(instanceId, elementRef, type, data, domChanges);
-    }
-  }
-
-  public List<InstanceOnFireEventInterceptor> getInstanceOnFireEventInterceptorList(){
-    if(this.mInstanceOnFireEventInterceptorList == null){
-      this.mInstanceOnFireEventInterceptorList = new ArrayList<>();
-    }
-    return mInstanceOnFireEventInterceptorList;
-  }
-
-
-  public void addInstanceOnFireEventInterceptor(InstanceOnFireEventInterceptor instanceOnFireEventInterceptor) {
-    if(instanceOnFireEventInterceptor == null){
-      return;
-    }
-    if(!getInstanceOnFireEventInterceptorList().contains(instanceOnFireEventInterceptor)){
-      getInstanceOnFireEventInterceptorList().add(instanceOnFireEventInterceptor);
-    }
-  }
-
-  public String getRenderType() {
-    return mRenderType;
-  }
-
-  public void setRenderType(String renderType) {
-    this.mRenderType = renderType;
-  }
-
-  private static boolean isDisableSkipFrameworkInDataRender() {
-    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
-    if (adapter == null) {
-      return false;
-    }
-    String result = adapter.getConfig("wxeagle", "disable_skip_framework_init", "false");
-    return "true".equals(result);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java
deleted file mode 100644
index c6c49d9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-
-import com.taobao.weex.adapter.ClassLoaderAdapter;
-import com.taobao.weex.adapter.DefaultUriAdapter;
-import com.taobao.weex.adapter.DefaultWXHttpAdapter;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.adapter.ICrashInfoReporter;
-import com.taobao.weex.adapter.IDrawableLoader;
-import com.taobao.weex.adapter.IWXJscProcessManager;
-import com.taobao.weex.adapter.ITracingAdapter;
-import com.taobao.weex.adapter.IWXAccessibilityRoleAdapter;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.adapter.IWXImgLoaderAdapter;
-import com.taobao.weex.adapter.IWXJSExceptionAdapter;
-import com.taobao.weex.adapter.IWXJsFileLoaderAdapter;
-import com.taobao.weex.adapter.IWXSoLoaderAdapter;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.appfram.navigator.IActivityNavBarSetter;
-import com.taobao.weex.appfram.navigator.INavigator;
-import com.taobao.weex.appfram.storage.DefaultWXStorage;
-import com.taobao.weex.appfram.storage.IWXStorageAdapter;
-import com.taobao.weex.appfram.websocket.IWebSocketAdapter;
-import com.taobao.weex.appfram.websocket.IWebSocketAdapterFactory;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.bridge.WXModuleManager;
-import com.taobao.weex.bridge.WXValidateProcessor;
-import com.taobao.weex.common.WXRefreshData;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.common.WXWorkThreadManager;
-import com.taobao.weex.font.FontAdapter;
-import com.taobao.weex.performance.IApmGenerator;
-import com.taobao.weex.performance.IWXAnalyzer;
-import com.taobao.weex.ui.WXRenderManager;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Manger class for weex context.
- */
-public class WXSDKManager {
-
-  private static volatile WXSDKManager sManager;
-  private static AtomicInteger sInstanceId = new AtomicInteger(0);
-  private final WXWorkThreadManager mWXWorkThreadManager;
-  private WXBridgeManager mBridgeManager;
-  /** package **/ WXRenderManager mWXRenderManager;
-
-  private IWXUserTrackAdapter mIWXUserTrackAdapter;
-  private IWXImgLoaderAdapter mIWXImgLoaderAdapter;
-  private IWXSoLoaderAdapter mIWXSoLoaderAdapter;
-  private IDrawableLoader mDrawableLoader;
-  private IWXHttpAdapter mIWXHttpAdapter;
-  private IActivityNavBarSetter mActivityNavBarSetter;
-  private IWXAccessibilityRoleAdapter mRoleAdapter;
-  private List<IWXAnalyzer> mWXAnalyzerList;
-  private IApmGenerator mApmGenerater;
-  private IWXJsFileLoaderAdapter mWXJsFileLoaderAdapter;
-
-  private ICrashInfoReporter mCrashInfo;
-
-  private IWXJSExceptionAdapter mIWXJSExceptionAdapter;
-
-  private IWXConfigAdapter mConfigAdapter;
-  private IWXStorageAdapter mIWXStorageAdapter;
-  private IWXStatisticsListener mStatisticsListener;
-  private URIAdapter mURIAdapter;
-  private ClassLoaderAdapter mClassLoaderAdapter;
-  private IWebSocketAdapterFactory mIWebSocketAdapterFactory;
-  private ITracingAdapter mTracingAdapter;
-  private WXValidateProcessor mWXValidateProcessor;
-  private IWXJscProcessManager mWXJscProcessManager;
-  // Tell weexv8 to initialize v8, default is true.
-  private boolean mNeedInitV8 = true;
-
-  //add when instance create,rm when instance destroy, not like WXRenderManager
-  private Map<String,WXSDKInstance> mAllInstanceMap;
-
-  private List<InstanceLifeCycleCallbacks> mLifeCycleCallbacks;
-
-  private static final int DEFAULT_VIEWPORT_WIDTH = 750;
-
-  private WXSDKManager() {
-    this(new WXRenderManager());
-  }
-
-  private WXSDKManager(WXRenderManager renderManager) {
-    mWXRenderManager = renderManager;
-    mBridgeManager = WXBridgeManager.getInstance();
-    mWXWorkThreadManager = new WXWorkThreadManager();
-    mWXAnalyzerList = new CopyOnWriteArrayList<>();
-    mAllInstanceMap = new HashMap<>();
-  }
-
-  /**
-   * Used in junit test
-   */
-  static void initInstance(WXRenderManager renderManager){
-    sManager = new WXSDKManager(renderManager);
-  }
-
-  public void registerStatisticsListener(IWXStatisticsListener listener) {
-    mStatisticsListener = listener;
-  }
-
-  public IWXStatisticsListener getWXStatisticsListener() {
-    return mStatisticsListener;
-  }
-
-  public void onSDKEngineInitialize() {
-    if (mStatisticsListener != null) {
-      mStatisticsListener.onSDKEngineInitialize();
-    }
-  }
-
-  public void setNeedInitV8(boolean need) {
-    mNeedInitV8 = need;
-  }
-
-  public boolean needInitV8() {
-    return mNeedInitV8;
-  }
-
-  public void takeJSHeapSnapshot(String path) {
-    File file = new File(path);
-    if (!file.exists()) {
-      if (!file.mkdir()) {
-        return;
-      }
-    }
-
-    String name = String.valueOf(sInstanceId.get());
-    String filename = path;
-
-    if (!path.endsWith(File.separator)) {
-      filename += File.separator;
-    }
-    filename += name;
-    filename += ".heapsnapshot";
-
-    mBridgeManager.takeJSHeapSnapshot(filename);
-  }
-
-  public static WXSDKManager getInstance() {
-    if (sManager == null) {
-      synchronized (WXSDKManager.class) {
-        if(sManager == null) {
-          sManager = new WXSDKManager();
-        }
-      }
-    }
-    return sManager;
-  }
-
-  public static int getInstanceViewPortWidth(String instanceId){
-    WXSDKInstance instance = getInstance().getSDKInstance(instanceId);
-    if (instance == null) {
-      return DEFAULT_VIEWPORT_WIDTH;
-    }
-    return instance.getInstanceViewPortWidth();
-  }
-
-  static void setInstance(WXSDKManager manager){
-    sManager = manager;
-  }
-
-  public IActivityNavBarSetter getActivityNavBarSetter() {
-    return mActivityNavBarSetter;
-  }
-
-  public void setActivityNavBarSetter(IActivityNavBarSetter mActivityNavBarSetter) {
-    this.mActivityNavBarSetter = mActivityNavBarSetter;
-  }
-
-  public void restartBridge() {
-    mBridgeManager.restart();
-  }
-
-  public WXBridgeManager getWXBridgeManager() {
-    return mBridgeManager;
-  }
-
-  public WXRenderManager getWXRenderManager() {
-    return mWXRenderManager;
-  }
-  public IWXJscProcessManager getWXJscProcessManager() {
-    return mWXJscProcessManager;
-  }
-  public WXWorkThreadManager getWXWorkThreadManager() {
-    return mWXWorkThreadManager;
-  }
-
-  public void setWxConfigAdapter(IWXConfigAdapter mConfigAdapter) {
-    this.mConfigAdapter = mConfigAdapter;
-  }
-
-  public IWXConfigAdapter getWxConfigAdapter() {
-    return mConfigAdapter;
-  }
-
-  public @Nullable WXSDKInstance getSDKInstance(String instanceId) {
-    return instanceId == null? null : mWXRenderManager.getWXSDKInstance(instanceId);
-  }
-
-  public void postOnUiThread(Runnable runnable, long delayMillis) {
-    mWXRenderManager.postOnUiThread(WXThread.secure(runnable), delayMillis);
-  }
-  public Map<String, WXSDKInstance> getAllInstanceMap() {
-    return mAllInstanceMap;
-  }
-
-  public void destroy() {
-    if (mWXWorkThreadManager != null) {
-      mWXWorkThreadManager.destroy();
-    }
-    mAllInstanceMap.clear();
-  }
-
-  @Deprecated
-  public void callback(String instanceId, String funcId, Map<String, Object> data) {
-    mBridgeManager.callback(instanceId, funcId, data);
-  }
-
-  @Deprecated
-  public void callback(String instanceId, String funcId, Map<String, Object> data,boolean keepAlive) {
-    mBridgeManager.callback(instanceId, funcId, data,keepAlive);
-  }
-
-  public void initScriptsFramework(String framework) {
-    mBridgeManager.initScriptsFramework(framework);
-  }
-
-  public void registerComponents(List<Map<String, Object>> components) {
-    mBridgeManager.registerComponents(components);
-  }
-
-  public void registerModules(Map<String, Object> modules) {
-    mBridgeManager.registerModules(modules);
-  }
-
-  /**
-   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
-   */
-  @Deprecated
-  public void fireEvent(final String instanceId, String ref, String type) {
-    fireEvent(instanceId, ref, type, new HashMap<String, Object>());
-  }
-
-  /**
-   * FireEvent back to JS
-   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
-   */
-  @Deprecated
-  public void fireEvent(final String instanceId, String ref, String type, Map<String, Object> params){
-    fireEvent(instanceId,ref,type,params,null);
-  }
-
-  /**
-   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
-   **/
-  @Deprecated
-  public void fireEvent(final String instanceId, String ref, String type, Map<String, Object> params,Map<String,Object> domChanges) {
-    if (WXEnvironment.isApkDebugable() && Looper.getMainLooper().getThread().getId() != Thread.currentThread().getId()) {
-      throw new WXRuntimeException("[WXSDKManager]  fireEvent error");
-    }
-    mBridgeManager.fireEventOnNode(instanceId, ref, type, params,domChanges);
-  }
-
-  void createInstance(WXSDKInstance instance, Script code, Map<String, Object> options, String jsonInitData) {
-    mWXRenderManager.registerInstance(instance);
-    mBridgeManager.createInstance(instance.getInstanceId(), code, options, jsonInitData);
-    if (mLifeCycleCallbacks != null) {
-      for (InstanceLifeCycleCallbacks callbacks : mLifeCycleCallbacks) {
-        callbacks.onInstanceCreated(instance.getInstanceId());
-      }
-    }
-  }
-
-  void refreshInstance(String instanceId, WXRefreshData jsonData) {
-    mBridgeManager.refreshInstance(instanceId, jsonData);
-  }
-
-  void destroyInstance(String instanceId) {
-    setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,"");
-    if (TextUtils.isEmpty(instanceId)) {
-      return;
-    }
-    if (!WXUtils.isUiThread()) {
-      throw new WXRuntimeException("[WXSDKManager] destroyInstance error");
-    }
-    if (mLifeCycleCallbacks != null) {
-      for (InstanceLifeCycleCallbacks callbacks : mLifeCycleCallbacks) {
-        callbacks.onInstanceDestroyed(instanceId);
-      }
-    }
-    mWXRenderManager.removeRenderStatement(instanceId);
-    mBridgeManager.destroyInstance(instanceId);
-    WXModuleManager.destroyInstanceModules(instanceId);
-  }
-
-  String generateInstanceId() {
-    return String.valueOf(sInstanceId.incrementAndGet());
-  }
-
-  public IWXUserTrackAdapter getIWXUserTrackAdapter() {
-    return mIWXUserTrackAdapter;
-  }
-
-  public IWXImgLoaderAdapter getIWXImgLoaderAdapter() {
-    return mIWXImgLoaderAdapter;
-  }
-
-  public IWXJsFileLoaderAdapter getIWXJsFileLoaderAdapter() {
-    return mWXJsFileLoaderAdapter;
-  }
-
-  public IDrawableLoader getDrawableLoader() {
-    return mDrawableLoader;
-  }
-
-  public IWXJSExceptionAdapter getIWXJSExceptionAdapter() {
-    return mIWXJSExceptionAdapter;
-  }
-
-  public void setIWXJSExceptionAdapter(IWXJSExceptionAdapter IWXJSExceptionAdapter) {
-    mIWXJSExceptionAdapter = IWXJSExceptionAdapter;
-  }
-
-  public @NonNull IWXHttpAdapter getIWXHttpAdapter() {
-    if (mIWXHttpAdapter == null) {
-      mIWXHttpAdapter = new DefaultWXHttpAdapter();
-    }
-    return mIWXHttpAdapter;
-  }
-
-  public IApmGenerator getApmGenerater() {
-    return mApmGenerater;
-  }
-
-  public @NonNull URIAdapter getURIAdapter() {
-    if(mURIAdapter == null){
-      mURIAdapter = new DefaultUriAdapter();
-    }
-    return mURIAdapter;
-  }
-
-  public ClassLoaderAdapter getClassLoaderAdapter() {
-    if(mClassLoaderAdapter == null){
-      mClassLoaderAdapter = new ClassLoaderAdapter();
-    }
-    return mClassLoaderAdapter;
-  }
-
-  public IWXSoLoaderAdapter getIWXSoLoaderAdapter() {
-    return mIWXSoLoaderAdapter;
-  }
-
-  public List<IWXAnalyzer> getWXAnalyzerList(){
-    return mWXAnalyzerList;
-  }
-
-  public void addWXAnalyzer(IWXAnalyzer analyzer){
-    if (!mWXAnalyzerList.contains(analyzer)) {
-      mWXAnalyzerList.add(analyzer);
-    }
-  }
-
-  public void rmWXAnalyzer(IWXAnalyzer analyzer){
-    mWXAnalyzerList.remove(analyzer);
-  }
-
-  void setInitConfig(InitConfig config){
-    this.mIWXHttpAdapter = config.getHttpAdapter();
-    this.mIWXImgLoaderAdapter = config.getImgAdapter();
-    this.mDrawableLoader = config.getDrawableLoader();
-    this.mIWXStorageAdapter = config.getStorageAdapter();
-    this.mIWXUserTrackAdapter = config.getUtAdapter();
-    this.mURIAdapter = config.getURIAdapter();
-    this.mIWebSocketAdapterFactory = config.getWebSocketAdapterFactory();
-    this.mIWXJSExceptionAdapter = config.getJSExceptionAdapter();
-    this.mIWXSoLoaderAdapter = config.getIWXSoLoaderAdapter();
-    this.mClassLoaderAdapter = config.getClassLoaderAdapter();
-    this.mApmGenerater = config.getApmGenerater();
-    this.mWXJsFileLoaderAdapter = config.getJsFileLoaderAdapter();
-    this.mWXJscProcessManager = config.getJscProcessManager();
-  }
-
-  public IWXStorageAdapter getIWXStorageAdapter(){
-    if(mIWXStorageAdapter == null){
-      if(WXEnvironment.sApplication != null){
-        mIWXStorageAdapter = new DefaultWXStorage(WXEnvironment.sApplication);
-      }else{
-        WXLogUtils.e("WXStorageModule", "No Application context found,you should call WXSDKEngine#initialize() method in your application");
-      }
-    }
-    return mIWXStorageAdapter;
-  }
-
-  /**
-   * Weex embedders can use <code>notifyTrimMemory</code> to reduce
-   * memory at a proper time.
-   *
-   * It's not a good idea to reduce memory at any time, because
-   * memory trimming is a expense operation, and V8 needs to do
-   * a full GC and all the inline caches get to be cleared.
-   *
-   * The embedder needs to make some scheduling strategies to
-   * ensure that the embedded application is just on an idle time.
-   * If the application use the same js bundle to render pages,
-   * it's not a good idea to trim memory every time of exiting
-   * pages.
-   */
-  public void notifyTrimMemory() {
-    mBridgeManager.notifyTrimMemory();
-  }
-
-  /**
-   * Weex embedders can use <code>notifySerializeCodeCache</code> to
-   * serialize code caches if the jsfm has the alility to compile 'new Function'
-   * against js bundles on the weex native side.
-   *
-   * It's a good time to serialize a code cache after exiting a weex page.
-   * Then, the next time of entering the same weex page, V8 would compile
-   * 'new Function' against the code cache deseriazed from the js bundle.
-   */
-  public void notifySerializeCodeCache() {
-    mBridgeManager.notifySerializeCodeCache();
-  }
-
-  public @Nullable
-  IWebSocketAdapter getIWXWebSocketAdapter() {
-    if (mIWebSocketAdapterFactory != null) {
-      return mIWebSocketAdapterFactory.createWebSocketAdapter();
-    }
-    return null;
-  }
-
-  public void registerValidateProcessor(WXValidateProcessor processor){
-    this.mWXValidateProcessor = processor;
-  }
-
-  public WXValidateProcessor getValidateProcessor(){
-    return mWXValidateProcessor;
-  }
-
-
-  public void setCrashInfoReporter(ICrashInfoReporter mCrashInfo) {
-    this.mCrashInfo = mCrashInfo;
-  }
-
-  public void setCrashInfo(String key, String value) {
-    if(mCrashInfo!=null){
-      mCrashInfo.addCrashInfo(key,value);
-    }
-  }
-
-  public void setTracingAdapter(ITracingAdapter adapter) {
-    this.mTracingAdapter = adapter;
-  }
-
-  public ITracingAdapter getTracingAdapter() {
-    return mTracingAdapter;
-  }
-
-  public void registerInstanceLifeCycleCallbacks(InstanceLifeCycleCallbacks callbacks) {
-    if (mLifeCycleCallbacks == null) {
-      mLifeCycleCallbacks = new ArrayList<>();
-    }
-    mLifeCycleCallbacks.add(callbacks);
-  }
-
-  public void setAccessibilityRoleAdapter(IWXAccessibilityRoleAdapter adapter) {
-    this.mRoleAdapter = adapter;
-  }
-
-  public IWXAccessibilityRoleAdapter getAccessibilityRoleAdapter() {
-    return mRoleAdapter;
-  }
-
-  public interface InstanceLifeCycleCallbacks {
-    void onInstanceDestroyed(String instanceId);
-    void onInstanceCreated(String instanceId);
-  }
-
-  private INavigator mNavigator;
-
-  public INavigator getNavigator() {
-    return mNavigator;
-  }
-
-  public void setNavigator(INavigator mNavigator) {
-    this.mNavigator = mNavigator;
-  }
-
-
-  private FontAdapter mFontAdapter;
-
-  public FontAdapter getFontAdapter(){
-      if(mFontAdapter == null){
-        synchronized (this){
-          if(mFontAdapter == null){
-              mFontAdapter = new FontAdapter();
-          }
-        }
-      }
-      return mFontAdapter;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/WeexFrameRateControl.java b/android/sdk/src/main/java/com/taobao/weex/WeexFrameRateControl.java
deleted file mode 100644
index eef4d5c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/WeexFrameRateControl.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-/**
- * Created by shiwentao on 2017/8/24.
- */
-
-import android.annotation.SuppressLint;
-import android.os.Build;
-import android.util.Log;
-import android.view.Choreographer;
-import com.taobao.weex.common.WXErrorCode;
-import java.lang.ref.WeakReference;
-
-public class WeexFrameRateControl {
-    private static final long VSYNC_FRAME = 1000 / 60;
-    private WeakReference<VSyncListener> mListener;
-    private final Choreographer mChoreographer;
-    private final Choreographer.FrameCallback mVSyncFrameCallback;
-    private final Runnable runnable;
-
-    public interface VSyncListener {
-        void OnVSync();
-    }
-
-    public WeexFrameRateControl(VSyncListener listener) {
-        mListener = new WeakReference<>(listener);
-        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-            mChoreographer = Choreographer.getInstance();
-            mVSyncFrameCallback = new Choreographer.FrameCallback() {
-                @SuppressLint("NewApi")
-                @Override
-                public void doFrame(long frameTimeNanos) {
-                    VSyncListener vSyncListener;
-                    if (mListener != null && (vSyncListener=mListener.get()) != null) {
-                        try {
-                            vSyncListener.OnVSync();
-                            mChoreographer.postFrameCallback(mVSyncFrameCallback);
-                        }catch (UnsatisfiedLinkError e){
-                            if(vSyncListener instanceof WXSDKInstance){
-                                ((WXSDKInstance) vSyncListener).onRenderError(
-                                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-                                    Log.getStackTraceString(e));
-                            }
-                        }
-                    }
-                }
-            };
-            runnable = null;
-        } else {
-            // For API 15 or lower
-            runnable = new Runnable() {
-                @Override
-                public void run() {
-                    VSyncListener vSyncListener;
-                    if (mListener != null && (vSyncListener = mListener.get()) != null) {
-                        try {
-                            vSyncListener.OnVSync();
-                            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(runnable, VSYNC_FRAME);
-                        }catch (UnsatisfiedLinkError e){
-                            if(vSyncListener instanceof WXSDKInstance){
-                                ((WXSDKInstance) vSyncListener).onRenderError(
-                                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-                                    Log.getStackTraceString(e));
-                            }
-                        }
-                    }
-                }
-            };
-            mChoreographer = null;
-            mVSyncFrameCallback = null;
-        }
-    }
-
-    @SuppressLint("NewApi")
-    public void start() {
-        if (mChoreographer != null) {
-            mChoreographer.postFrameCallback(mVSyncFrameCallback);
-        }
-        else if(runnable!=null){
-            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(runnable, VSYNC_FRAME);
-        }
-    }
-
-    @SuppressLint("NewApi")
-    public void stop() {
-        if (mChoreographer != null) {
-            mChoreographer.removeFrameCallback(mVSyncFrameCallback);
-        }else if(runnable!=null){
-            WXSDKManager.getInstance().getWXRenderManager().removeTask(runnable);
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/ClassLoaderAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/ClassLoaderAdapter.java
deleted file mode 100644
index 7d6a854..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/ClassLoaderAdapter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.content.Context;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by furture on 2018/2/7.
- * class loader adapter for load auto config class.
- */
-public class ClassLoaderAdapter {
-
-    /**
-     * context is module class
-     * */
-    public Class<? extends WXModule> getModuleClass(String name, String className, Context context){
-        try {
-            return (Class<? extends WXModule>) context.getClassLoader().loadClass(className);
-        } catch (ClassNotFoundException e) {
-            throw  new RuntimeException(e);
-        }
-    }
-
-    /**
-     * context is instance context
-     */
-    public Class<? extends WXComponent> getComponentClass(String name, String className, WXSDKInstance instance) {
-        try {
-            return (Class<? extends WXComponent>) instance.getContext().getClassLoader().loadClass(className);
-        } catch (ClassNotFoundException e) {
-            throw  new RuntimeException(e);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/DefaultUriAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/DefaultUriAdapter.java
deleted file mode 100644
index de77e87..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/DefaultUriAdapter.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-
-import java.util.List;
-
-
-/**
- * Default Uri adapter. Provide basic capability to handle relative path, local file path etc.
- * Created by sospartan on 21/11/2016.
- */
-public class DefaultUriAdapter implements URIAdapter {
-
-
-  @NonNull
-  @Override
-  public Uri rewrite(WXSDKInstance instance, String type, Uri uri) {
-    return rewrite(instance.getBundleUrl(), type, uri);
-  }
-
-  @NonNull
-  @Override
-  public Uri rewrite(String bundleURL, String type, Uri uri) {
-    if (TextUtils.isEmpty(bundleURL)) {
-      return uri;
-    }
-
-    Uri base = Uri.parse(bundleURL);
-    Uri.Builder resultBuilder = uri.buildUpon();
-
-    if (uri.isRelative()) {
-      //When uri is empty, means use the base url instead. Web broswer behave this way.
-      if(uri.getEncodedPath().length() == 0){
-        if(URIAdapter.IMAGE.equals(type)){
-          if(TextUtils.isEmpty(uri.toString())){
-            return uri;
-          }
-        }
-        return base;
-      } else {
-        resultBuilder = buildRelativeURI(resultBuilder, base, uri);
-        return resultBuilder.build();
-      }
-    }
-    return uri;
-  }
-
-  private Uri.Builder buildRelativeURI(Uri.Builder resultBuilder, Uri base, Uri uri) {
-    if (uri.getAuthority() != null) {
-      return resultBuilder.scheme(base.getScheme());
-    } else {
-      resultBuilder
-          .encodedAuthority(base.getEncodedAuthority())
-          .scheme(base.getScheme())
-          .path(null);
-
-      if (uri.getPath().startsWith("/")) {
-        //relative to root
-        resultBuilder.appendEncodedPath(uri.getEncodedPath().substring(1));
-      } else {
-        List<String> segments = base.getPathSegments();
-        //ignore last segment if not end with /
-        int ignoreLast = 1;
-        if (base.getPath().endsWith("/")) {
-          ignoreLast = 0;
-        }
-        for (int i = 0, len = segments.size() - ignoreLast; i < len; i++) {
-          resultBuilder.appendEncodedPath(segments.get(i));
-        }
-        resultBuilder.appendEncodedPath(uri.getEncodedPath());
-      }
-      return resultBuilder;
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/DefaultWXHttpAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/DefaultWXHttpAdapter.java
deleted file mode 100644
index 2d26765..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/DefaultWXHttpAdapter.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.common.WXResponse;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-
-public class DefaultWXHttpAdapter implements IWXHttpAdapter {
-
-  private static final IEventReporterDelegate DEFAULT_DELEGATE = new NOPEventReportDelegate();
-  private ExecutorService mExecutorService;
-
-  private void execute(Runnable runnable){
-    if(mExecutorService==null){
-      mExecutorService = Executors.newFixedThreadPool(3);
-    }
-    mExecutorService.execute(runnable);
-  }
-
-  @Override
-  public void sendRequest(final WXRequest request, final OnHttpListener listener) {
-    if (listener != null) {
-      listener.onHttpStart();
-    }
-    execute(new Runnable() {
-      @Override
-      public void run() {
-        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(request.instanceId);
-        if (null != instance && !instance.isDestroy()){
-          instance.getApmForInstance().actionNetRequest();
-        }
-
-        boolean isNetRequestSucceed = true;
-
-        WXResponse response = new WXResponse();
-        IEventReporterDelegate reporter = getEventReporterDelegate();
-        try {
-          HttpURLConnection connection = openConnection(request, listener);
-          reporter.preConnect(connection, request.body);
-          Map<String,List<String>> headers = connection.getHeaderFields();
-          int responseCode = connection.getResponseCode();
-          if(listener != null){
-            listener.onHeadersReceived(responseCode,headers);
-          }
-          reporter.postConnect();
-
-          response.statusCode = String.valueOf(responseCode);
-          if (responseCode >= 200 && responseCode<=299) {
-            InputStream rawStream = connection.getInputStream();
-            rawStream = reporter.interpretResponseStream(rawStream);
-            response.originalData = readInputStreamAsBytes(rawStream, listener);
-          } else {
-            response.errorMsg = readInputStream(connection.getErrorStream(), listener);
-            isNetRequestSucceed = false;
-          }
-          if (listener != null) {
-            listener.onHttpFinish(response);
-          }
-        } catch (IOException|IllegalArgumentException e) {
-          isNetRequestSucceed = false;
-          e.printStackTrace();
-          response.statusCode = "-1";
-          response.errorCode="-1";
-          response.errorMsg=e.getMessage();
-          if(listener!=null){
-            listener.onHttpFinish(response);
-          }
-          if (e instanceof IOException) {
-            try {
-              reporter.httpExchangeFailed((IOException) e);
-            } catch (Throwable t) {
-              t.printStackTrace();
-            }
-          }
-        }
-        if (null != instance && !instance.isDestroy()){
-          instance.getApmForInstance().actionNetResult(isNetRequestSucceed,null);
-        }
-      }
-    });
-  }
-
-
-  /**
-   * Opens an {@link HttpURLConnection} with parameters.
-   *
-   * @param request
-   * @param listener
-   * @return an open connection
-   * @throws IOException
-   */
-  private HttpURLConnection openConnection(WXRequest request, OnHttpListener listener) throws IOException {
-    URL url = new URL(request.url);
-    HttpURLConnection connection = createConnection(url);
-    connection.setConnectTimeout(request.timeoutMs);
-    connection.setReadTimeout(request.timeoutMs);
-    connection.setUseCaches(false);
-    connection.setDoInput(true);
-
-    if (request.paramMap != null) {
-      Set<String> keySets = request.paramMap.keySet();
-      for (String key : keySets) {
-        connection.addRequestProperty(key, request.paramMap.get(key));
-      }
-    }
-
-    if ("POST".equals(request.method) || "PUT".equals(request.method) || "PATCH".equals(request.method)) {
-      connection.setRequestMethod(request.method);
-      if (request.body != null) {
-        if (listener != null) {
-          listener.onHttpUploadProgress(0);
-        }
-        connection.setDoOutput(true);
-        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
-        //TODO big stream will cause OOM; Progress callback is meaningless
-        out.write(request.body.getBytes());
-        out.close();
-        if (listener != null) {
-          listener.onHttpUploadProgress(100);
-        }
-      }
-    } else if (!TextUtils.isEmpty(request.method)) {
-      connection.setRequestMethod(request.method);
-    } else {
-      connection.setRequestMethod("GET");
-    }
-
-    return connection;
-  }
-
-  private byte[] readInputStreamAsBytes(InputStream inputStream,OnHttpListener listener) throws IOException{
-    if(inputStream == null){
-      return null;
-    }
-    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-
-    int nRead;
-    int readCount = 0;
-    byte[] data = new byte[2048];
-
-    while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
-      buffer.write(data, 0, nRead);
-      readCount += nRead;
-      if (listener != null) {
-        listener.onHttpResponseProgress(readCount);
-      }
-    }
-
-    buffer.flush();
-
-    return buffer.toByteArray();
-  }
-
-  private String readInputStream(InputStream inputStream, OnHttpListener listener) throws IOException {
-    if(inputStream == null){
-      return null;
-    }
-    StringBuilder builder = new StringBuilder();
-    BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(inputStream));
-    char[] data = new char[2048];
-    int len;
-    while ((len = localBufferedReader.read(data)) != -1) {
-      builder.append(data, 0, len);
-      if (listener != null) {
-        listener.onHttpResponseProgress(builder.length());
-      }
-    }
-    localBufferedReader.close();
-    return builder.toString();
-  }
-
-  /**
-   * Create an {@link HttpURLConnection} for the specified {@code url}.
-   */
-  protected HttpURLConnection createConnection(URL url) throws IOException {
-    return (HttpURLConnection) url.openConnection();
-  }
-
-  public @NonNull IEventReporterDelegate getEventReporterDelegate() {
-    return DEFAULT_DELEGATE;
-  }
-
-  public interface IEventReporterDelegate {
-    void preConnect(HttpURLConnection connection, @Nullable String body);
-    void postConnect();
-    InputStream interpretResponseStream(@Nullable InputStream inputStream);
-    void httpExchangeFailed(IOException e);
-  }
-
-  private static class NOPEventReportDelegate implements IEventReporterDelegate {
-    @Override
-    public void preConnect(HttpURLConnection connection, @Nullable String body) {
-      //do nothing
-    }
-
-    @Override
-    public void postConnect() {
-      //do nothing
-    }
-
-    @Override
-    public InputStream interpretResponseStream(@Nullable InputStream inputStream) {
-      return inputStream;
-    }
-
-    @Override
-    public void httpExchangeFailed(IOException e) {
-      //do nothing
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java b/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java
deleted file mode 100644
index c6daa5a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-
-public class DrawableStrategy {
-
-  public int width;
-  public int height;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/ICrashInfoReporter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/ICrashInfoReporter.java
deleted file mode 100644
index 54c15cc..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/ICrashInfoReporter.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-/**
- * Created by zhengshihan on 2017/5/23.
- */
-
-public interface ICrashInfoReporter {
-  void addCrashInfo(String key ,String value);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IDrawableLoader.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IDrawableLoader.java
deleted file mode 100644
index 080d3b5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IDrawableLoader.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
-
-public interface IDrawableLoader {
-
-  interface DrawableTarget {
-    void setDrawable(@Nullable Drawable drawable, boolean resetBounds);
-  }
-
-  interface StaticTarget extends DrawableTarget{
-    void setDrawable(@Nullable Drawable drawable, boolean resetBounds);
-  }
-
-  interface AnimatedTarget extends DrawableTarget{
-    void setAnimatedDrawable(@Nullable Drawable drawable);
-  }
-
-  void setDrawable(String url, DrawableTarget drawableTarget, DrawableStrategy drawableStrategy);
-}
-
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/ITracingAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/ITracingAdapter.java
deleted file mode 100644
index 4acb23d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/ITracingAdapter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import com.taobao.weex.tracing.WXTracing;
-
-/**
- * Created by moxun on 2017/7/6.
- */
-
-public interface ITracingAdapter {
-  void enable();
-  void disable();
-  void submitTracingEvent(WXTracing.TraceEvent event);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXAccessibilityRoleAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXAccessibilityRoleAdapter.java
deleted file mode 100644
index 46ca77f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXAccessibilityRoleAdapter.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-/**
- * Created by moxun on 2017/11/13.
- */
-
-public interface IWXAccessibilityRoleAdapter {
-  String getRole(String key);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXConfigAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXConfigAdapter.java
deleted file mode 100644
index 953bf2c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXConfigAdapter.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-/**
- * @author zhongcang
- * @date 2019/3/20
- */
-public interface IWXConfigAdapter {
-    String getConfig(String nameSpace,String key,String defaultValue);
-    String getConfigWhenInit(String nameSpace,String key,String defaultValue);
-    boolean checkMode(String name);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXHttpAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXHttpAdapter.java
deleted file mode 100644
index 3d6ea1f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXHttpAdapter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-
-import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.common.WXResponse;
-
-import java.util.List;
-import java.util.Map;
-
-public interface IWXHttpAdapter {
-
-  /**
-   * http request method
-   *
-   * @param request weex assemble request
-   * @param listener http response notify
-   */
-  void sendRequest(WXRequest request, OnHttpListener listener);
-
-  interface OnHttpListener {
-
-    /**
-     * start request
-     */
-    void onHttpStart();
-
-    /**
-     * headers received
-     */
-    void onHeadersReceived(int statusCode,Map<String,List<String>> headers);
-
-    /**
-     * post progress
-     * @param uploadProgress
-     */
-    void onHttpUploadProgress(int uploadProgress);
-
-    /**
-     * response loaded length (bytes), full length should read from headers (content-length)
-     * @param loadedLength
-     */
-    void onHttpResponseProgress(int loadedLength);
-
-    /**
-     * http response finish
-     * @param response
-     */
-    void onHttpFinish(WXResponse response);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXImgLoaderAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXImgLoaderAdapter.java
deleted file mode 100644
index 4b03ba8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXImgLoaderAdapter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.widget.ImageView;
-
-import com.taobao.weex.common.WXImageStrategy;
-import com.taobao.weex.dom.WXImageQuality;
-
-/**
- * Interface for ImageLoader. This interface works as an adapter for various image library.
- */
-public interface IWXImgLoaderAdapter {
-
-  void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy strategy);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJSExceptionAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJSExceptionAdapter.java
deleted file mode 100644
index 12ea4d8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJSExceptionAdapter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import com.taobao.weex.common.WXJSExceptionInfo;
-
-public interface IWXJSExceptionAdapter {
-
-  /**
-   * report js exception
-   *
-   * @param exception {@link WXJSExceptionInfo}
-   */
-
-  void onJSException(WXJSExceptionInfo exception);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJsFileLoaderAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJsFileLoaderAdapter.java
deleted file mode 100644
index 37bbf7f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJsFileLoaderAdapter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-public interface IWXJsFileLoaderAdapter {
-    String loadRaxApi();
-    String loadJsFramework();
-    String loadJsFrameworkForSandBox();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJscProcessManager.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJscProcessManager.java
deleted file mode 100644
index 4c8d22a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXJscProcessManager.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import com.taobao.weex.WXSDKInstance;
-
-public interface IWXJscProcessManager {
-    boolean enableBackupThread();
-    boolean enableBackUpThreadCache();
-    boolean shouldReboot();
-    long rebootTimeout();
-    boolean withException(WXSDKInstance instance);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXSoLoaderAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXSoLoaderAdapter.java
deleted file mode 100644
index fb9614a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXSoLoaderAdapter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-/**
- * Interface for loading library.
- */
-public interface IWXSoLoaderAdapter {
-  /**
-   * A method <code>doLoadLibrary</code> that
-   * helps embedders to load a shared library with a short name.
-   * <p>
-   *
-   * Embedders would have a chance to take charge of library loading,
-   * they could load libraries with different class loaders,
-   * or load libraries from specified library pathes.
-   *
-   * @param shortName the name of the library
-   */
-  void doLoadLibrary(String shortName);
-
-  /**
-   * A method <code>doLoad</code> that
-   * helps embedders to load a shared library.
-   * <p>
-   *
-   * Embedders would have a chance to take charge of library loading,
-   * they could load libraries with different class loaders,
-   * or load libraries from specified library pathes.
-   *
-   * @param name the file to load.
-   */
-  void doLoad(String name);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXUserTrackAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/IWXUserTrackAdapter.java
deleted file mode 100644
index 915399e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/IWXUserTrackAdapter.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.content.Context;
-
-import com.taobao.weex.common.WXPerformance;
-
-import java.io.Serializable;
-import java.util.Map;
-
-/**
- * Interface for commit log info. This interface works as an adapter for various log library.
- */
-public interface IWXUserTrackAdapter {
-
-  String MODULE_NAME = "weex";
-
-  //Performance
-  String LOAD = "load";
-
-  //Alarm
-  String JS_FRAMEWORK = "jsFramework";
-  String JS_DOWNLOAD = "jsDownload";
-  String DOM_MODULE = "domModule";
-  String JS_BRIDGE = "jsBridge";
-  String STREAM_MODULE = "streamModule";
-  String INVOKE_MODULE = "invokeModule";
-  String INIT_FRAMEWORK = "initFramework";
-  String COUNTER = "counter";
-
-  /**
-   * monitor keys
-   */
-  String MONITOR_ERROR_CODE = "errCode";
-  String MONITOR_ARG = "arg";
-  String MONITOR_ERROR_MSG = "errMsg";
-
-  void commit(Context context, String eventId, String type, WXPerformance perf, Map<String, Serializable> params);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/URIAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/URIAdapter.java
deleted file mode 100644
index cdac2fd..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/adapter/URIAdapter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.taobao.weex.WXSDKInstance;
-
-/**
- * Created by sospartan on 15/11/2016.
- */
-
-public interface URIAdapter {
-
-  /**
-   * Stream request url.
-   */
-  String REQUEST = "request";
-
-  /**
-   * URI for image src.
-   */
-  String IMAGE = "image";
-
-  /**
-   * Font file URI for text @font-face .
-   */
-  String FONT = "font";
-
-  /**
-   * Video URI.
-   */
-  String VIDEO = "video";
-
-  /**
-   * URI for a 'href' attribute.
-   */
-  String LINK = "link";
-
-  /**
-   * Bundle URI for Weex instance.
-   */
-  String BUNDLE = "bundle";
-
-  /**
-   * Web page src
-   */
-  String WEB = "web";
-
-  /**
-   * Unknown URIs.
-   */
-  String OTHERS = "others";
-
-  /**
-   *
-   * @param type URI type, see {@link #IMAGE}/{@link #LINK}/{@link #FONT}/{@link #BUNDLE}/{@link #VIDEO}/{@link #OTHERS}
-   * @param uri
-   * @return
-   */
-  @NonNull Uri rewrite(WXSDKInstance instance, String type, Uri uri);
-  @NonNull Uri rewrite(String bundleURL, String type, Uri uri);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/annotation/Component.java b/android/sdk/src/main/java/com/taobao/weex/annotation/Component.java
deleted file mode 100644
index 3f3414c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/annotation/Component.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Created by sospartan on 6/12/16.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface Component {
-  boolean lazyload() default true;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/annotation/JSMethod.java b/android/sdk/src/main/java/com/taobao/weex/annotation/JSMethod.java
deleted file mode 100644
index 443dc37..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/annotation/JSMethod.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Created by sospartan on 19/10/2016.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Inherited
-@Target(ElementType.METHOD)
-public @interface JSMethod {
-  boolean uiThread() default true;
-
-  String alias() default NOT_SET;
-
-  String NOT_SET = "_";
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/clipboard/IWXClipboard.java b/android/sdk/src/main/java/com/taobao/weex/appfram/clipboard/IWXClipboard.java
deleted file mode 100644
index ccccd31..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/clipboard/IWXClipboard.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.clipboard;
-
-import android.support.annotation.Nullable;
-
-import com.taobao.weex.bridge.JSCallback;
-
-/**
- * Created by yiyuan.zhangyy(xingjiu) <br/>
- */
-interface IWXClipboard {
-    public void setString(String text);
-    public void getString(@Nullable JSCallback callback);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/clipboard/WXClipboardModule.java b/android/sdk/src/main/java/com/taobao/weex/appfram/clipboard/WXClipboardModule.java
deleted file mode 100644
index 7ded68a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/clipboard/WXClipboardModule.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.clipboard;
-
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.AssetFileDescriptor;
-import android.net.Uri;
-import android.support.annotation.Nullable;
-
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.HashMap;
-import java.util.Map;
-
-
-public class WXClipboardModule extends WXModule implements IWXClipboard {
-
-    private final String CLIP_KEY = "WEEX_CLIP_KEY_MAIN";
-
-    private static final String RESULT = "result";
-    private static final String DATA = "data";
-
-    private static final String RESULT_OK = "success";
-    private static final String RESULT_FAILED = "failed";
-
-    @Override
-    @JSMethod
-    public void setString(String text) {
-        if(null == text) {
-            return;
-        }
-
-        Context context = mWXSDKInstance.getContext();
-        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(context.CLIPBOARD_SERVICE);
-        ClipData clip = ClipData.newPlainText(CLIP_KEY, text);
-        clipboard.setPrimaryClip(clip);
-    }
-
-    @Override
-    @JSMethod
-    public void getString(@Nullable JSCallback callback) {
-        Context context = mWXSDKInstance.getContext();
-        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
-
-        Map<String, Object> map = new HashMap<>(2);
-        ClipData clip = clipboard.getPrimaryClip();
-        if (clip != null && clip.getItemCount() > 0) {
-            ClipData.Item item = clip.getItemAt(0);
-            CharSequence text = coerceToText(context, item);
-
-            map.put(RESULT, text != null ? RESULT_OK : RESULT_FAILED);
-            map.put(DATA, text != null ? text : "");
-        } else {
-            map.put(RESULT, RESULT_FAILED);
-            map.put(DATA, "");
-        }
-
-        if (null != callback) {
-            callback.invoke(map);
-        }
-    }
-
-    @Nullable
-    private CharSequence coerceToText(Context context, ClipData.Item item) {
-        // Condition 1. just a simple text
-        CharSequence text = item.getText();
-        if (text != null) {
-            return text;
-        }
-
-        // Condition 2. a URI value
-        Uri uri = item.getUri();
-        if (uri != null) {
-            InputStreamReader reader = null;
-            FileInputStream stream = null;
-            try {
-                AssetFileDescriptor assetFileDescriptor = context.getContentResolver().openTypedAssetFileDescriptor(uri, "text/*", null);
-                stream = assetFileDescriptor.createInputStream();
-                reader = new InputStreamReader(stream, "UTF-8");
-
-                StringBuilder builder = new StringBuilder(128);
-                char[] buffer = new char[8192];
-                int len;
-                while ((len = reader.read(buffer)) > 0) {
-                    builder.append(buffer, 0, len);
-                }
-                return builder.toString();
-
-            } catch (FileNotFoundException e) {
-                //  ignore.
-            } catch (IOException e) {
-                WXLogUtils.w("ClippedData Failure loading text.", e);
-            } finally {
-                if (reader != null) {
-                    try {
-                        reader.close();
-                    } catch (IOException e) {
-                        // ignore
-                    }
-                }
-                if (stream != null) {
-                    try {
-                        stream.close();
-                    } catch (IOException e) {
-                        // ignore
-                    }
-                }
-            }
-
-            return uri.toString();
-        }
-
-        // Condition 3.  an intent.
-        Intent intent = item.getIntent();
-        if (intent != null) {
-            return intent.toUri(Intent.URI_INTENT_SCHEME);
-        }
-
-        // else case
-        return null;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/IActivityNavBarSetter.java b/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/IActivityNavBarSetter.java
deleted file mode 100644
index 321991d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/IActivityNavBarSetter.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.navigator;
-
-/**
- *  Define the  NavBarSetter api of the Activity
- */
-public interface IActivityNavBarSetter {
-
-  boolean push(String param);
-
-  boolean pop(String param);
-
-  boolean setNavBarRightItem(String param);
-
-  boolean clearNavBarRightItem(String param);
-
-  boolean setNavBarLeftItem(String param);
-
-  boolean clearNavBarLeftItem(String param);
-
-  boolean setNavBarMoreItem(String param);
-
-  boolean clearNavBarMoreItem(String param);
-
-  boolean setNavBarTitle(String param);
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/INavigator.java b/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/INavigator.java
deleted file mode 100644
index 65c7193..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/INavigator.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.navigator;
-import android.app.Activity;
-
-/**
- * Created by zhengshihan on 2018/8/9.
- */
-
-public interface INavigator {
-
-  boolean push(Activity activity,String param);
-
-  boolean pop(Activity activity,String param);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/WXNavigatorModule.java b/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/WXNavigatorModule.java
deleted file mode 100644
index 69c253b..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/navigator/WXNavigatorModule.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.navigator;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.support.v7.app.AppCompatActivity;
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.utils.WXLogUtils;
-
-
-public class WXNavigatorModule extends WXModule {
-
-    public static final String MSG_SUCCESS = "WX_SUCCESS";
-    public static final String MSG_FAILED = "WX_FAILED";
-    public static final String MSG_PARAM_ERR = "WX_PARAM_ERR";
-
-    public static final String CALLBACK_RESULT = "result";
-    public static final String CALLBACK_MESSAGE = "message";
-
-    private final static String INSTANCE_ID = "instanceId";
-    private final static String TAG = "Navigator";
-    private final static String WEEX = "com.taobao.android.intent.category.WEEX";
-    private final static String URL = "url";
-
-    @JSMethod(uiThread = true)
-    public void open(JSONObject options, JSCallback success, JSCallback failure) {
-        if (options != null) {
-            String url = options.getString(Constants.Value.URL);
-            JSCallback callback = success;
-            JSONObject result = new JSONObject();
-            if (!TextUtils.isEmpty(url)) {
-                Uri rawUri = Uri.parse(url);
-                String scheme = rawUri.getScheme();
-                if (TextUtils.isEmpty(scheme) || Constants.Scheme.HTTP.equalsIgnoreCase(scheme) || Constants.Scheme.HTTPS.equalsIgnoreCase(scheme)) {
-                    this.push(options.toJSONString(), success);
-                } else {
-                    try {
-                        Intent intent = new Intent(Intent.ACTION_VIEW, rawUri);
-                        mWXSDKInstance.getContext().startActivity(intent);
-                        result.put(CALLBACK_RESULT, MSG_SUCCESS);
-                    } catch (Throwable e) {
-                        e.printStackTrace();
-                        result.put(CALLBACK_RESULT, MSG_FAILED);
-                        result.put(CALLBACK_MESSAGE, "Open page failed.");
-                        callback = failure;
-                    }
-                }
-            } else {
-                result.put(CALLBACK_RESULT, MSG_PARAM_ERR);
-                result.put(CALLBACK_MESSAGE, "The URL parameter is empty.");
-                callback = failure;
-            }
-
-            if(callback != null){
-                callback.invoke(result);
-            }
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void close(JSONObject options, JSCallback success, JSCallback failure) {
-        JSONObject result = new JSONObject();
-        JSCallback callback = null;
-        if (mWXSDKInstance.getContext() instanceof Activity) {
-            callback = success;
-            ((Activity) mWXSDKInstance.getContext()).finish();
-        } else {
-            result.put(CALLBACK_RESULT, MSG_FAILED);
-            result.put(CALLBACK_MESSAGE, "Close page failed.");
-            callback = failure;
-        }
-        if (callback != null) {
-            callback.invoke(result);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void push(String param, JSCallback callback) {
-
-        if (!TextUtils.isEmpty(param)) {
-            if (WXSDKEngine.getActivityNavBarSetter() != null) {
-                if (WXSDKEngine.getActivityNavBarSetter().push(param)) {
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                    return;
-                }
-            }
-
-            if (mWXSDKInstance.getContext() instanceof Activity){
-                Activity activity = (Activity)mWXSDKInstance.getContext();
-
-                if (WXSDKEngine.getNavigator()!= null
-                    && WXSDKEngine.getNavigator().push(activity,param)) {
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                    return;
-                }
-            }
-
-            try {
-                JSONObject jsonObject = JSON.parseObject(param);
-                String url = jsonObject.getString(URL);
-                if (!TextUtils.isEmpty(url)) {
-                    Uri rawUri = Uri.parse(url);
-                    String scheme = rawUri.getScheme();
-                    Uri.Builder builder = rawUri.buildUpon();
-                    if (TextUtils.isEmpty(scheme)) {
-                        builder.scheme(Constants.Scheme.HTTP);
-                    }
-                    Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
-                    intent.addCategory(WEEX);
-                    intent.putExtra(INSTANCE_ID, mWXSDKInstance.getInstanceId());
-                    mWXSDKInstance.getContext().startActivity(intent);
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                }
-            } catch (Exception e) {
-                WXLogUtils.eTag(TAG, e);
-                if (callback != null) {
-                    callback.invoke(MSG_FAILED);
-                }
-            }
-        } else if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void pop(String param, JSCallback callback) {
-
-        if (WXSDKEngine.getActivityNavBarSetter() != null) {
-            if (WXSDKEngine.getActivityNavBarSetter().pop(param)) {
-                if (callback != null) {
-                    callback.invoke(MSG_SUCCESS);
-                }
-                return;
-            }
-        }
-
-        if (mWXSDKInstance.getContext() instanceof Activity) {
-            Activity activity = (Activity) mWXSDKInstance.getContext();
-            if (WXSDKEngine.getNavigator() != null) {
-                if (WXSDKEngine.getNavigator().pop(activity, param)) {
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                    return;
-                }
-            }
-
-            if (callback != null) {
-                callback.invoke(MSG_SUCCESS);
-            }
-            ((Activity) mWXSDKInstance.getContext()).finish();
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void setNavBarRightItem(String param, JSCallback callback) {
-        if (!TextUtils.isEmpty(param)) {
-            if (WXSDKEngine.getActivityNavBarSetter() != null) {
-                if (WXSDKEngine.getActivityNavBarSetter().setNavBarRightItem(param)) {
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                    return;
-                }
-            }
-        }
-
-        if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void clearNavBarRightItem(String param, JSCallback callback) {
-        if (WXSDKEngine.getActivityNavBarSetter() != null) {
-            if (WXSDKEngine.getActivityNavBarSetter().clearNavBarRightItem(param)) {
-                if (callback != null) {
-                    callback.invoke(MSG_SUCCESS);
-                }
-                return;
-            }
-        }
-        if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void setNavBarLeftItem(String param, JSCallback callback) {
-        if (!TextUtils.isEmpty(param)) {
-            if (WXSDKEngine.getActivityNavBarSetter() != null) {
-                if (WXSDKEngine.getActivityNavBarSetter().setNavBarLeftItem(param)) {
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                    return;
-                }
-            }
-        }
-
-        if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-
-    }
-
-    @JSMethod(uiThread = true)
-    public void clearNavBarLeftItem(String param, JSCallback callback) {
-        if (WXSDKEngine.getActivityNavBarSetter() != null) {
-            if (WXSDKEngine.getActivityNavBarSetter().clearNavBarLeftItem(param)) {
-                if (callback != null) {
-                    callback.invoke(MSG_SUCCESS);
-                }
-                return;
-            }
-        }
-
-        if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void setNavBarMoreItem(String param, JSCallback callback) {
-        if (!TextUtils.isEmpty(param)) {
-            if (WXSDKEngine.getActivityNavBarSetter() != null) {
-                if (WXSDKEngine.getActivityNavBarSetter().setNavBarMoreItem(param)) {
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                    return;
-                }
-            }
-        }
-
-        if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void clearNavBarMoreItem(String param, JSCallback callback) {
-        if (WXSDKEngine.getActivityNavBarSetter() != null) {
-            if (WXSDKEngine.getActivityNavBarSetter().clearNavBarMoreItem(param)) {
-                if (callback != null) {
-                    callback.invoke(MSG_SUCCESS);
-                }
-                return;
-            }
-        }
-
-        if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void setNavBarTitle(String param, JSCallback callback) {
-        if (!TextUtils.isEmpty(param)) {
-            if (WXSDKEngine.getActivityNavBarSetter() != null) {
-                if (WXSDKEngine.getActivityNavBarSetter().setNavBarTitle(param)) {
-                    if (callback != null) {
-                        callback.invoke(MSG_SUCCESS);
-                    }
-                    return;
-                }
-            }
-        }
-        if (callback != null) {
-            callback.invoke(MSG_FAILED);
-        }
-    }
-
-    @JSMethod
-    public void setNavBarHidden(String param, final String callback) {
-        String message = MSG_FAILED;
-        try {
-            JSONObject jsObj = JSON.parseObject(param);
-            int visibility = jsObj.getInteger(Constants.Name.NAV_BAR_VISIBILITY);
-            boolean success = changeVisibilityOfActionBar(mWXSDKInstance.getContext(), visibility);
-            if (success) {
-                message = MSG_SUCCESS;
-            }
-        } catch (JSONException e) {
-            WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
-        }
-        WXBridgeManager.getInstance().callback(mWXSDKInstance.getInstanceId(), callback, message);
-    }
-
-    private boolean changeVisibilityOfActionBar(Context context, int visibility) {
-        boolean result = false;
-        boolean hasAppCompatActivity = false;
-        try {
-            Class.forName("android.support.v7.app.AppCompatActivity");
-            hasAppCompatActivity = true;
-        } catch (ClassNotFoundException e) {
-            e.printStackTrace();
-        }
-        if (hasAppCompatActivity && mWXSDKInstance.getContext() instanceof AppCompatActivity) {
-            android.support.v7.app.ActionBar actionbar = ((AppCompatActivity) mWXSDKInstance.getContext()).getSupportActionBar();
-            if (actionbar != null) {
-                switch (visibility) {
-                    case Constants.Value.NAV_BAR_HIDDEN:
-                        actionbar.hide();
-                        result = true;
-                        break;
-                    case Constants.Value.NAV_BAR_SHOWN:
-                        actionbar.show();
-                        result = true;
-                        break;
-                }
-            }
-        } else if (mWXSDKInstance.getContext() instanceof Activity) {
-            android.app.ActionBar actionbar = ((Activity) mWXSDKInstance.getContext()).getActionBar();
-            if (actionbar != null) {
-                switch (visibility) {
-                    case Constants.Value.NAV_BAR_HIDDEN:
-                        actionbar.hide();
-                        result = true;
-                        break;
-                    case Constants.Value.NAV_BAR_SHOWN:
-                        actionbar.show();
-                        result = true;
-                        break;
-                }
-            }
-        }
-        return result;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/pickers/DatePickerImpl.java b/android/sdk/src/main/java/com/taobao/weex/appfram/pickers/DatePickerImpl.java
deleted file mode 100644
index 7aca328..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/pickers/DatePickerImpl.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.pickers;
-
-import android.app.AlertDialog;
-import android.app.DatePickerDialog;
-import android.app.TimePickerDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.widget.Button;
-import android.widget.DatePicker;
-import android.widget.TimePicker;
-
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Created by moxun on 16/11/23.
- */
-
-public class DatePickerImpl {
-
-    private static final int DEFAULT_START_YEAR = 1900;
-    private static final int DEFAULT_END_YEAR = 2100;
-
-    private static SimpleDateFormat timeFormatter;
-    private static SimpleDateFormat dateFormatter;
-
-    public static void pickDate(@NonNull Context context, String value, String max, String min, @NonNull final OnPickListener listener, @Nullable Map<String, Object> extras) {
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(parseDate(value));
-        final DatePickerDialog dialog = new DatePickerDialog(
-                context,
-                new DatePickerDialog.OnDateSetListener() {
-                    @Override
-                    public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
-                        int realMonth = monthOfYear + 1;
-                        String realMonthString = realMonth < 10 ? "0" + realMonth : String.valueOf(realMonth);
-                        String realDayString = dayOfMonth < 10 ? "0" + dayOfMonth : String.valueOf(dayOfMonth);
-                        String result = year + "-" + realMonthString + "-" + realDayString;
-                        listener.onPick(true, result);
-                    }
-                },
-                calendar.get(Calendar.YEAR),
-                calendar.get(Calendar.MONTH),
-                calendar.get(Calendar.DAY_OF_MONTH)
-        );
-
-        final DatePicker datePicker = dialog.getDatePicker();
-
-        final Calendar defaultMinDate = Calendar.getInstance(Locale.getDefault());
-        final Calendar defaultMaxDate = Calendar.getInstance(Locale.getDefault());
-
-        defaultMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
-        defaultMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
-
-        if (!TextUtils.isEmpty(min)) {
-            long minDate = parseDate(min).getTime();
-            if (datePicker.getMaxDate() >= minDate) {
-                datePicker.setMinDate(parseDate(min).getTime());
-            } else {
-                datePicker.setMinDate(defaultMinDate.getTimeInMillis());
-                datePicker.setMaxDate(defaultMaxDate.getTimeInMillis());
-            }
-        }
-        if (!TextUtils.isEmpty(max)) {
-            long maxDate = parseDate(max).getTime();
-            if (datePicker.getMinDate() <= maxDate) {
-                datePicker.setMaxDate(parseDate(max).getTime());
-            } else {
-                datePicker.setMinDate(defaultMinDate.getTimeInMillis());
-                datePicker.setMaxDate(defaultMaxDate.getTimeInMillis());
-            }
-        }
-
-        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-            @Override
-            public void onCancel(DialogInterface dialog) {
-                listener.onPick(false, null);
-            }
-        });
-
-        setButtonText(dialog, DialogInterface.BUTTON_NEGATIVE, String.valueOf(extras != null ? extras.get("cancelTitle") : null));
-        setButtonText(dialog, DialogInterface.BUTTON_POSITIVE, String.valueOf(extras != null ? extras.get("confirmTitle") : null));
-
-        dialog.show();
-    }
-
-    public static void pickTime(@NonNull Context context, String value, @NonNull final OnPickListener listener, @Nullable Map<String, Object> extras) {
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(parseTime(value));
-        TimePickerDialog dialog = new TimePickerDialog(
-                context,
-                new TimePickerDialog.OnTimeSetListener() {
-                    @Override
-                    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
-                        String h = hourOfDay < 10 ? "0" + hourOfDay : String.valueOf(hourOfDay);
-                        String m = minute < 10 ? "0" + minute : String.valueOf(minute);
-                        String result = h + ":" + m;
-                        listener.onPick(true, result);
-                    }
-                },
-                calendar.get(Calendar.HOUR_OF_DAY),
-                calendar.get(Calendar.MINUTE),
-                false
-        );
-
-        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-            @Override
-            public void onCancel(DialogInterface dialog) {
-                listener.onPick(false, null);
-            }
-        });
-
-        setButtonText(dialog, DialogInterface.BUTTON_NEGATIVE, String.valueOf(extras != null ? extras.get("cancelTitle") : null));
-        setButtonText(dialog, DialogInterface.BUTTON_POSITIVE, String.valueOf(extras != null ? extras.get("confirmTitle") : null));
-
-        dialog.show();
-    }
-
-    public interface OnPickListener {
-        void onPick(boolean set, @Nullable String result);
-    }
-
-    private static Date parseDate(String s) {
-        if (dateFormatter == null) {
-            dateFormatter = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
-        }
-
-        try {
-            return dateFormatter.parse(s);
-        } catch (ParseException e) {
-            //don't worry
-            WXLogUtils.w("[DatePickerImpl] " + e.toString());
-        }
-        return new Date();
-    }
-
-    private static Date parseTime(String s) {
-        if (timeFormatter == null) {
-            timeFormatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
-        }
-
-        try {
-            return timeFormatter.parse(s);
-        } catch (ParseException e) {
-            //don't worry
-            WXLogUtils.w("[DatePickerImpl] " + e.toString());
-        }
-        return new Date();
-    }
-
-    private static void setButtonText(final AlertDialog dialog, final int which, final CharSequence text) {
-        if (TextUtils.isEmpty(text) || "null".equals(text)) {
-            return;
-        }
-        try {
-            dialog.getWindow().getDecorView().post(WXThread.secure(new Runnable() {
-                @Override
-                public void run() {
-                    Button button = dialog.getButton(which);
-                    if (button != null) {
-                        button.setAllCaps(false);
-                        button.setText(text);
-                    }
-                }
-            }));
-        } catch (Throwable t) {
-            t.printStackTrace();
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/pickers/WXPickersModule.java b/android/sdk/src/main/java/com/taobao/weex/appfram/pickers/WXPickersModule.java
deleted file mode 100644
index ef46f8f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/pickers/WXPickersModule.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.pickers;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.graphics.Color;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.Checkable;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by moxun on 16/10/27.
- */
-
-public class WXPickersModule extends WXModule {
-
-    private static final String SUCCESS = "success";
-    private static final String CANCEL = "cancel";
-    private static final String ERROR = "error";
-
-    private static final String RESULT = "result";
-    private static final String DATA = "data";
-
-    private static final String KEY_VALUE = "value";
-    private static final String KEY_INDEX = "index";
-    private static final String KEY_TITLE = "title";
-    private static final String KEY_MAX = "max";
-    private static final String KEY_MIN = "min";
-    private static final String KEY_ITEMS = "items";
-
-    private static final String KEY_TITLE_COLOR = "titleColor";
-    private static final String KEY_CANCEL_TITLE_COLOR = "cancelTitleColor";
-    private static final String KEY_CONFIRM_TITLE = "confirmTitle";
-    private static final String KEY_CANCEL_TITLE = "cancelTitle";
-    private static final String KEY_CONFIRM_TITLE_COLOR = "confirmTitleColor";
-    private static final String KEY_TITLE_BACKGROUND_COLOR = "titleBackgroundColor";
-    private static final String KEY_TEXT_COLOR = "textColor";
-    private static final String KEY_SELECTION_COLOR = "selectionColor";
-
-    private int selected;
-
-    @JSMethod
-    public void pick(Map<String, Object> options, JSCallback callback) {
-        List<String> items = safeConvert(getOption(options, KEY_ITEMS, new ArrayList<String>()));
-        try {
-            performSinglePick(items, options, callback);
-        } catch (Throwable throwable) {
-            throwable.printStackTrace();
-        }
-    }
-
-    @JSMethod
-    public void pickDate(Map<String, Object> options, JSCallback callback) {
-        performPickDate(options, callback);
-    }
-
-    @JSMethod
-    public void pickTime(Map<String, Object> options, JSCallback callback) {
-        performPickTime(options, callback);
-    }
-
-    private List<String> safeConvert(List src) {
-        List<String> result = new ArrayList<>(src.size());
-        for (Object obj : src) {
-            result.add(String.valueOf(obj));
-        }
-        return result;
-    }
-
-    private <T> T getOption(Map<String, Object> options, String key, T defValue) {
-        Object value = options.get(key);
-        if (value == null) {
-            return defValue;
-        } else {
-            try {
-                return (T) value;
-            } catch (Exception e) {
-                e.printStackTrace();
-                return defValue;
-            }
-        }
-    }
-
-    private int getColor(Map<String, Object> options, String key, int defValue) {
-        Object value = getOption(options, key, null);
-        if (value == null) {
-            return defValue;
-        }
-        return WXResourceUtils.getColor(value.toString(), defValue);
-    }
-
-    private void performPickTime(Map<String, Object> options, final JSCallback callback) {
-        String value = getOption(options, KEY_VALUE, "");
-        DatePickerImpl.pickTime(
-                mWXSDKInstance.getContext(),
-                value,
-                new DatePickerImpl.OnPickListener() {
-                    @Override
-                    public void onPick(boolean set, @Nullable String result) {
-                        if (set) {
-                            Map<String, Object> ret = new HashMap<>(2);
-                            ret.put(RESULT, SUCCESS);
-                            ret.put(DATA, result);
-                            callback.invoke(ret);
-                        } else {
-                            Map<String, Object> ret = new HashMap<>(2);
-                            ret.put(RESULT, CANCEL);
-                            ret.put(DATA, null);
-                            callback.invoke(ret);
-                        }
-                    }
-                },
-                options);
-    }
-
-    private void performPickDate(Map<String, Object> options, final JSCallback callback) {
-        String value = getOption(options, KEY_VALUE, "");
-        String max = getOption(options, KEY_MAX, "");
-        String min = getOption(options, KEY_MIN, "");
-        DatePickerImpl.pickDate(
-                mWXSDKInstance.getContext(),
-                value,
-                max,
-                min,
-                new DatePickerImpl.OnPickListener() {
-                    @Override
-                    public void onPick(boolean set, @Nullable String result) {
-                        if (set) {
-                            Map<String, Object> ret = new HashMap<>(2);
-                            ret.put(RESULT, SUCCESS);
-                            ret.put(DATA, result);
-                            callback.invoke(ret);
-                        } else {
-                            Map<String, Object> ret = new HashMap<>(2);
-                            ret.put(RESULT, CANCEL);
-                            ret.put(DATA, null);
-                            callback.invoke(ret);
-                        }
-                    }
-                },
-                options);
-
-    }
-
-    private void performSinglePick(final List<String> items, final Map<String, Object> options, final JSCallback callback) {
-        selected = getOption(options, KEY_INDEX, 0);
-        final int textColor = getColor(options, KEY_TEXT_COLOR, Color.TRANSPARENT);
-        final int selectionColor = getColor(options, KEY_SELECTION_COLOR, Color.TRANSPARENT);
-        final ArrayAdapter adapter = new ArrayAdapter<String>(
-            mWXSDKInstance.getContext(),
-            android.R.layout.simple_list_item_single_choice,
-            items) {
-            @NonNull
-            @Override
-            public View getView(int position, View convertView, @Nullable ViewGroup parent) {
-                View itemView =  super.getView(position, convertView, parent);
-
-                if (itemView != null && itemView instanceof Checkable) {
-                    boolean needSelected = position == selected;
-                    ((Checkable) itemView).setChecked(needSelected);
-
-                    if (needSelected) {
-                        itemView.setBackgroundColor(selectionColor);
-                    } else {
-                        itemView.setBackgroundColor(Color.TRANSPARENT);
-                    }
-                }
-
-                if (itemView instanceof TextView && textColor != Color.TRANSPARENT) {
-                    ((TextView) itemView).setTextColor(textColor);
-                }
-
-                return itemView;
-            }
-        };
-        final AlertDialog dialog =  new AlertDialog.Builder(mWXSDKInstance.getContext())
-                .setAdapter(adapter, null)
-                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        //which == -1
-                        Map<String, Object> ret = new HashMap<>(2);
-                        ret.put(RESULT, SUCCESS);
-                        ret.put(DATA, selected);
-                        callback.invoke(ret);
-                    }
-                })
-                .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        //which == -2
-                        Map<String, Object> ret = new HashMap<>(2);
-                        ret.put(RESULT, CANCEL);
-                        ret.put(DATA, -1);
-                        callback.invoke(ret);
-                    }
-                })
-                .setCustomTitle(makeTitleView(mWXSDKInstance.getContext(), options))
-                .create();
-
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            //pre create the content view on dialog.
-            //if not , the content view will not be created until dialog.show() called
-            dialog.create();
-        }
-
-        final ListView listView = dialog.getListView();
-        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                selected = position;
-                adapter.notifyDataSetChanged();
-            }
-        });
-
-        dialog.getWindow().getDecorView().post(WXThread.secure(new Runnable() {
-            @Override
-            public void run() {
-                Button confirm = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
-                Button cancel = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
-
-                if (confirm != null) {
-                    String confirmTitle = getOption(options, KEY_CONFIRM_TITLE, null);
-                    int confirmColor = getColor(options, KEY_CONFIRM_TITLE_COLOR, Color.TRANSPARENT);
-
-                    if (confirmTitle != null) {
-                        confirm.setText(confirmTitle);
-                        confirm.setAllCaps(false);
-                    }
-
-                    if (confirmColor != Color.TRANSPARENT) {
-                        confirm.setTextColor(confirmColor);
-                        confirm.setAllCaps(false);
-                    }
-                }
-
-                if (cancel != null) {
-                    String cancelTitle = getOption(options, KEY_CANCEL_TITLE, null);
-                    int cancelColor = getColor(options, KEY_CANCEL_TITLE_COLOR, Color.TRANSPARENT);
-
-                    if (cancelTitle != null) {
-                        cancel.setText(cancelTitle);
-                    }
-
-                    if (cancelColor != Color.TRANSPARENT) {
-                        cancel.setTextColor(cancelColor);
-                    }
-                }
-            }
-        }));
-
-        dialog.show();
-    }
-
-    private TextView makeTitleView(Context context, Map<String, Object> options) {
-        String text = getOption(options, KEY_TITLE, null);
-        if (text == null) {
-            return null;
-        }
-        TextView textView = new TextView(context);
-        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
-        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
-        int padding = WXViewUtils.dip2px(12);
-        textView.setPadding(padding, padding, padding, padding);
-        textView.getPaint().setFakeBoldText(true);
-        textView.setBackgroundColor(getColor(options, KEY_TITLE_BACKGROUND_COLOR, Color.TRANSPARENT));
-        textView.setTextColor(getColor(options, KEY_TITLE_COLOR, Color.BLACK));
-        textView.setText(text);
-        return textView;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/DefaultWXStorage.java b/android/sdk/src/main/java/com/taobao/weex/appfram/storage/DefaultWXStorage.java
deleted file mode 100644
index 9bcc75e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/DefaultWXStorage.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteFullException;
-import android.database.sqlite.SQLiteStatement;
-import android.support.annotation.Nullable;
-
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class DefaultWXStorage implements IWXStorageAdapter {
-
-    private WXSQLiteOpenHelper mDatabaseSupplier;
-
-    private ExecutorService mExecutorService;
-
-    private void execute(@Nullable final Runnable runnable) {
-        if (mExecutorService == null) {
-            mExecutorService = Executors.newSingleThreadExecutor();
-        }
-
-        if(runnable != null && !mExecutorService.isShutdown() && !mExecutorService.isTerminated()) {
-            mExecutorService.execute(WXThread.secure(runnable));
-        }
-    }
-
-    public DefaultWXStorage(Context context) {
-        this.mDatabaseSupplier = new WXSQLiteOpenHelper(context);
-    }
-
-
-    @Override
-    public void setItem(final String key, final String value, final OnResultReceivedListener listener) {
-        execute(new Runnable() {
-            @Override
-            public void run() {
-                Map<String, Object> data = StorageResultHandler.setItemResult(performSetItem(key, value, false, true));
-                if (listener == null) {
-                    return;
-                }
-                listener.onReceived(data);
-            }
-        });
-    }
-
-    @Override
-    public void getItem(final String key, final OnResultReceivedListener listener) {
-        execute(new Runnable() {
-            @Override
-            public void run() {
-                Map<String, Object> data = StorageResultHandler.getItemResult(performGetItem(key));
-                if (listener == null) {
-                    return;
-                }
-                listener.onReceived(data);
-            }
-        });
-    }
-
-    @Override
-    public void removeItem(final String key, final OnResultReceivedListener listener) {
-        execute(new Runnable() {
-            @Override
-            public void run() {
-                Map<String, Object> data = StorageResultHandler.removeItemResult(performRemoveItem(key));
-                if (listener == null) {
-                    return;
-                }
-                listener.onReceived(data);
-            }
-        });
-    }
-
-    @Override
-    public void length(final OnResultReceivedListener listener) {
-        execute(new Runnable() {
-            @Override
-            public void run() {
-                Map<String, Object> data = StorageResultHandler.getLengthResult(performGetLength());
-                if (listener == null) {
-                    return;
-                }
-                listener.onReceived(data);
-            }
-        });
-    }
-
-    @Override
-    public void getAllKeys(final OnResultReceivedListener listener) {
-        execute(new Runnable() {
-            @Override
-            public void run() {
-                Map<String, Object> data = StorageResultHandler.getAllkeysResult(performGetAllKeys());
-                if (listener == null) {
-                    return;
-                }
-                listener.onReceived(data);
-            }
-        });
-    }
-
-    @Override
-    public void setItemPersistent(final String key, final String value, final OnResultReceivedListener listener) {
-        execute(new Runnable() {
-            @Override
-            public void run() {
-                Map<String, Object> data = StorageResultHandler.setItemResult(performSetItem(key, value, true, true));
-                if (listener == null) {
-                    return;
-                }
-                listener.onReceived(data);
-            }
-        });
-    }
-
-    @Override
-    public void close() {
-        final ExecutorService needCloseService = mExecutorService;
-        execute(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mDatabaseSupplier.closeDatabase();
-                    if (needCloseService != null) {
-                        needCloseService.shutdown();
-                    }
-                } catch (Exception e) {
-                    WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, e.getMessage());
-                }
-            }
-        });
-        mExecutorService = null;
-    }
-
-    private boolean performSetItem(String key, String value, boolean isPersistent, boolean allowRetryWhenFull) {
-        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
-        if (database == null) {
-            return false;
-        }
-
-        WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE, "set k-v to storage(key:" + key + ",value:" + value + ",isPersistent:" + isPersistent + ",allowRetry:" + allowRetryWhenFull + ")");
-        String sql = "INSERT OR REPLACE INTO " + WXSQLiteOpenHelper.TABLE_STORAGE + " VALUES (?,?,?,?);";
-        SQLiteStatement statement = null;
-        String timeStamp = WXSQLiteOpenHelper.sDateFormatter.format(new Date());
-        try {
-            statement = database.compileStatement(sql);
-            statement.clearBindings();
-            statement.bindString(1, key);
-            statement.bindString(2, value);
-            statement.bindString(3, timeStamp);
-            statement.bindLong(4, isPersistent ? 1 : 0);
-            statement.execute();
-            return true;
-        } catch (Exception e) {
-            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute setItem :" + e.getMessage());
-            if (e instanceof SQLiteFullException) {
-                if (allowRetryWhenFull && trimToSize()) {
-                    //try again
-                    //setItem/setItemPersistent method only allow try once when occurred a sqliteFullException.
-                    WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE, "retry set k-v to storage(key:" + key + ",value:" + value + ")");
-                    return performSetItem(key, value, isPersistent, false);
-                }
-            }
-
-            return false;
-        } finally {
-            if(statement != null) {
-                statement.close();
-            }
-        }
-    }
-
-    /**
-     * remove 10% of total record(at most) ordered by timestamp.
-     * */
-    private boolean trimToSize() {
-        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
-        if (database == null) {
-            return false;
-        }
-
-        List<String> toEvict = new ArrayList<>();
-        int num = 0;
-
-        Cursor c = database.query(WXSQLiteOpenHelper.TABLE_STORAGE, new String[]{WXSQLiteOpenHelper.COLUMN_KEY, WXSQLiteOpenHelper.COLUMN_PERSISTENT}, null, null, null, null, WXSQLiteOpenHelper.COLUMN_TIMESTAMP + " ASC");
-        try {
-            int evictSize = c.getCount() / 10;
-            while (c.moveToNext()) {
-                String key = c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_KEY));
-                boolean persistent = c.getInt(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_PERSISTENT)) == 1;
-                if (!persistent && key != null) {
-                    num++;
-                    toEvict.add(key);
-                    if (num == evictSize) {
-                        break;
-                    }
-                }
-            }
-        } catch (Exception e) {
-            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute trimToSize:" + e.getMessage());
-        } finally {
-            c.close();
-        }
-
-        if (num <= 0) {
-            return false;
-        }
-
-        for (String key : toEvict) {
-            performRemoveItem(key);
-        }
-        WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "remove " + num + " items by lru");
-        return true;
-    }
-
-    private String performGetItem(String key) {
-        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
-        if (database == null) {
-            return null;
-        }
-
-        Cursor c = database.query(WXSQLiteOpenHelper.TABLE_STORAGE,
-                new String[]{WXSQLiteOpenHelper.COLUMN_VALUE},
-                WXSQLiteOpenHelper.COLUMN_KEY + "=?",
-                new String[]{key},
-                null, null, null);
-        try {
-            if (c.moveToNext()) {
-                ContentValues values = new ContentValues();
-                //update timestamp
-                values.put(WXSQLiteOpenHelper.COLUMN_TIMESTAMP, WXSQLiteOpenHelper.sDateFormatter.format(new Date()));
-                int updateResult = mDatabaseSupplier.getDatabase().update(WXSQLiteOpenHelper.TABLE_STORAGE, values, WXSQLiteOpenHelper.COLUMN_KEY + "= ?", new String[]{key});
-
-                WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE, "update timestamp " + (updateResult == 1 ? "success" : "failed") + " for operation [getItem(key = " + key + ")]");
-                return c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_VALUE));
-            } else {
-                return null;
-            }
-        } catch (Exception e) {
-            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute getItem:" + e.getMessage());
-            return null;
-        } finally {
-            c.close();
-        }
-    }
-
-    private boolean performRemoveItem(String key) {
-        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
-        if (database == null) {
-            return false;
-        }
-
-        int count = 0;
-        try {
-            count = database.delete(WXSQLiteOpenHelper.TABLE_STORAGE,
-                    WXSQLiteOpenHelper.COLUMN_KEY + "=?",
-                    new String[]{key});
-        } catch (Exception e) {
-            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute removeItem:" + e.getMessage());
-            return false;
-        }
-        return count == 1;
-    }
-
-    private long performGetLength() {
-        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
-        if (database == null) {
-            return 0;
-        }
-
-        String sql = "SELECT count(" + WXSQLiteOpenHelper.COLUMN_KEY + ") FROM " + WXSQLiteOpenHelper.TABLE_STORAGE;
-        SQLiteStatement statement = null;
-        try {
-            statement = database.compileStatement(sql);
-            return statement.simpleQueryForLong();
-        } catch (Exception e) {
-            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute getLength:" + e.getMessage());
-            return 0;
-        } finally {
-            if(statement != null) {
-                statement.close();
-            }
-        }
-    }
-
-    private List<String> performGetAllKeys() {
-        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
-        if (database == null) {
-            return null;
-        }
-
-        List<String> result = new ArrayList<>();
-        Cursor c = database.query(WXSQLiteOpenHelper.TABLE_STORAGE, new String[]{WXSQLiteOpenHelper.COLUMN_KEY}, null, null, null, null, null);
-        try {
-            while (c.moveToNext()) {
-                result.add(c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_KEY)));
-            }
-            return result;
-        } catch (Exception e) {
-            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute getAllKeys:" + e.getMessage());
-            return result;
-        } finally {
-            c.close();
-        }
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/IWXStorage.java b/android/sdk/src/main/java/com/taobao/weex/appfram/storage/IWXStorage.java
deleted file mode 100644
index c869d53..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/IWXStorage.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import android.support.annotation.Nullable;
-
-import com.taobao.weex.bridge.JSCallback;
-
-interface IWXStorage {
-    public void setItem(String key, String value,@Nullable JSCallback callback);
-    public void getItem(String key,@Nullable JSCallback callback);
-    public void removeItem(String key,@Nullable JSCallback callback);
-    public void length(@Nullable JSCallback callback);
-    public void getAllKeys(@Nullable JSCallback callback);
-    public void setItemPersistent(String key, String value, @Nullable JSCallback callback);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/IWXStorageAdapter.java b/android/sdk/src/main/java/com/taobao/weex/appfram/storage/IWXStorageAdapter.java
deleted file mode 100644
index c04512c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/IWXStorageAdapter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import java.util.Map;
-
-/**
- * interface for {@link WXStorageModule} class.
- * this interface works as an adapter for different storage strategy.
- * the default is use {@link android.database.sqlite.SQLiteDatabase} to store k-v pairs.
- * You can call {@link com.taobao.weex.InitConfig.Builder#setStorageAdapter(IWXStorageAdapter)} to inject your own
- * storage implementation.
- * */
-public interface IWXStorageAdapter {
-    void setItem(String key, String value,OnResultReceivedListener listener);
-
-    void getItem(String key,OnResultReceivedListener listener);
-
-    void removeItem(String key,OnResultReceivedListener listener);
-
-    void length(OnResultReceivedListener listener);
-
-    void getAllKeys(OnResultReceivedListener listener);
-
-    void setItemPersistent(String key, String value, OnResultReceivedListener listener);
-
-    void close();
-
-    /**
-     * the callback of storage operation.
-     * */
-    interface OnResultReceivedListener {
-        void onReceived(Map<String,Object> data);
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/StorageResultHandler.java b/android/sdk/src/main/java/com/taobao/weex/appfram/storage/StorageResultHandler.java
deleted file mode 100644
index f8be207..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/StorageResultHandler.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import android.support.annotation.Nullable;
-
-import com.taobao.weex.bridge.JSCallback;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class StorageResultHandler {
-
-    private StorageResultHandler() {
-    }
-
-    private static final String RESULT = "result";
-    private static final String DATA = "data";
-
-
-    private static final String UNDEFINED = "undefined";
-    private static final String RESULT_FAILED_NO_HANDLER = "no_handler";
-    private static final String RESULT_FAILED_INVALID_PARAM = "invalid_param";
-
-
-    private static final String RESULT_OK = "success";
-    private static final String RESULT_FAILED = "failed";
-
-
-    public static Map<String, Object> getItemResult(String result) {
-        Map<String, Object> map = new HashMap<>(4);
-        map.put(RESULT, result != null ? RESULT_OK : RESULT_FAILED);
-        map.put(DATA, result != null ? result : UNDEFINED);
-        return map;
-    }
-
-    public static Map<String, Object> setItemResult(boolean result) {
-        Map<String, Object> map = new HashMap<>(4);
-        map.put(RESULT, result ? RESULT_OK : RESULT_FAILED);
-        map.put(DATA, UNDEFINED);
-        return map;
-    }
-
-
-    public static Map<String, Object> removeItemResult(boolean result) {
-        Map<String, Object> map = new HashMap<>(4);
-        map.put(RESULT, result ? RESULT_OK : RESULT_FAILED);
-        map.put(DATA, UNDEFINED);
-        return map;
-    }
-
-    public static Map<String, Object> getLengthResult(long result) {
-        Map<String, Object> map = new HashMap<>(4);
-        map.put(RESULT, RESULT_OK);
-        map.put(DATA, result);
-        return map;
-    }
-
-    public static Map<String, Object> getAllkeysResult(List<String> result) {
-        if (result == null) {
-            result = new ArrayList<>(1);
-        }
-        Map<String, Object> map = new HashMap<>(4);
-        map.put(RESULT, RESULT_OK);
-        map.put(DATA, result);
-        return map;
-    }
-
-
-    private static void handleResult(@Nullable JSCallback callback, String result, Object data) {
-        if (callback == null) {
-            return;
-        }
-        Map<String, Object> retVal = new HashMap<>(4);
-        retVal.put(RESULT, result);
-        retVal.put(DATA, data);
-        callback.invoke(retVal);
-    }
-
-    public static void handleNoHandlerError(@Nullable JSCallback callback) {
-        handleResult(callback, RESULT_FAILED, RESULT_FAILED_NO_HANDLER);
-    }
-
-    public static void handleInvalidParam(@Nullable JSCallback callback) {
-        handleResult(callback, RESULT_FAILED, RESULT_FAILED_INVALID_PARAM);
-    }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/WXSQLiteOpenHelper.java b/android/sdk/src/main/java/com/taobao/weex/appfram/storage/WXSQLiteOpenHelper.java
deleted file mode 100644
index 4477030..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/WXSQLiteOpenHelper.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-public class WXSQLiteOpenHelper extends SQLiteOpenHelper {
-
-    private static final String DATABASE_NAME = "WXStorage";
-    private static final int DATABASE_VERSION = 2;
-    static final String TAG_STORAGE = "weex_storage";
-
-    private long mMaximumDatabaseSize = 5 * 10 * 1024 * 1024L;//50mb
-    static SimpleDateFormat sDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
-    private Context mContext;
-    private SQLiteDatabase mDb;
-
-
-    static final String TABLE_STORAGE = "default_wx_storage";
-    static final String COLUMN_KEY = "key";
-    static final String COLUMN_VALUE = "value";
-    static final String COLUMN_TIMESTAMP = "timestamp";
-    static final String COLUMN_PERSISTENT = "persistent";
-
-    private static final int SLEEP_TIME_MS = 30;
-
-    private static final String STATEMENT_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_STORAGE + " ("
-            + COLUMN_KEY
-            + " TEXT PRIMARY KEY,"
-            + COLUMN_VALUE
-            + " TEXT NOT NULL,"
-            + COLUMN_TIMESTAMP
-            + " TEXT NOT NULL,"
-            + COLUMN_PERSISTENT
-            + " INTEGER DEFAULT 0"
-            + ")";
-
-
-    public WXSQLiteOpenHelper(Context context) {
-        super(context, DATABASE_NAME, null, DATABASE_VERSION);
-        this.mContext = context;
-    }
-
-    /**
-     * retrieve sqlite database
-     *
-     * @return a {@link SQLiteDatabase} instance or null if retrieve fails.
-     * */
-    public @Nullable SQLiteDatabase getDatabase() {
-        ensureDatabase();
-        return mDb;
-    }
-
-    @Override
-    public void onCreate(SQLiteDatabase db) {
-        db.execSQL(STATEMENT_CREATE_TABLE);
-    }
-
-
-    /**
-     * version 1:
-     *
-     *   ----------------
-     *   | key | value |
-     *   ---------------
-     *
-     * version 2:
-     *
-     *  ----------------------------------------
-     *  | key | value | timestamp | persistent |
-     *  ----------------------------------------
-     **/
-    @Override
-    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-        if (oldVersion != newVersion) {
-            if(newVersion == 2 && oldVersion == 1){
-                WXLogUtils.d(TAG_STORAGE,"storage is updating from version "+oldVersion+" to version "+newVersion);
-                boolean updateResult = true;
-                try {
-                    long start = System.currentTimeMillis();
-
-                    db.beginTransaction();
-                    // update table structure
-                    String SQL_ADD_COLUMN_TIMESTAMP = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_TIMESTAMP+" TEXT;";
-                    WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_TIMESTAMP);
-                    db.execSQL(SQL_ADD_COLUMN_TIMESTAMP);
-
-                    String SQL_ADD_COLUMN_PERSISTENT = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_PERSISTENT+" INTEGER;";
-                    WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_PERSISTENT);
-                    db.execSQL(SQL_ADD_COLUMN_PERSISTENT);
-
-                    // update timestamp & persistent
-                    String SQL_UPDATE_TABLE = "UPDATE "+TABLE_STORAGE+" SET "+ COLUMN_TIMESTAMP+" = '"+sDateFormatter.format(new Date())+"' , "+ COLUMN_PERSISTENT +" = 0";
-                    WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_UPDATE_TABLE);
-                    db.execSQL(SQL_UPDATE_TABLE);
-
-                    db.setTransactionSuccessful();
-                    long time = System.currentTimeMillis() - start;
-                    WXLogUtils.d(TAG_STORAGE,"storage updated success ("+time+"ms)");
-                }catch (Exception e){
-                    WXLogUtils.d(TAG_STORAGE,"storage updated failed from version "+oldVersion+" to version "+newVersion+","+e.getMessage());
-                    updateResult = false;
-                }finally {
-                    db.endTransaction();
-                }
-                //rollback
-                if(!updateResult){
-                    WXLogUtils.d(TAG_STORAGE,"storage is rollback,all data will be removed");
-                    deleteDB();
-                    onCreate(db);
-                }
-            }else{
-                deleteDB();
-                onCreate(db);
-            }
-        }
-    }
-
-
-
-    synchronized void ensureDatabase() {
-        if (mDb != null && mDb.isOpen()) {
-            return;
-        }
-
-        try {
-            // Sometimes retrieving the database fails. We do 2 retries: first without database deletion
-            // and then with deletion.
-            for (int tries = 0; tries < 2; tries++) {
-                try {
-                    if (tries > 0) {
-                        //delete db and recreate
-                        deleteDB();
-                    }
-                    mDb = getWritableDatabase();
-                    break;
-                } catch (SQLiteException e) {
-                    e.printStackTrace();
-                }
-                // Wait before retrying.
-                try {
-                    Thread.sleep(SLEEP_TIME_MS);
-                } catch (InterruptedException ie) {
-                    Thread.currentThread().interrupt();
-                }
-            }
-            if(mDb == null){
-                return;
-            }
-
-            createTableIfNotExists(mDb);
-
-            mDb.setMaximumSize(mMaximumDatabaseSize);
-        } catch (Throwable e) {
-            mDb = null;
-            WXLogUtils.d(TAG_STORAGE,"ensureDatabase failed, throwable = " + e.getMessage());
-        }
-
-    }
-
-    public synchronized void setMaximumSize(long size) {
-        mMaximumDatabaseSize = size;
-        if (mDb != null) {
-            mDb.setMaximumSize(mMaximumDatabaseSize);
-        }
-    }
-
-    private boolean deleteDB() {
-        closeDatabase();
-        return mContext.deleteDatabase(DATABASE_NAME);
-    }
-
-    public synchronized void closeDatabase() {
-        if (mDb != null && mDb.isOpen()) {
-            mDb.close();
-            mDb = null;
-        }
-    }
-
-    private void createTableIfNotExists(@NonNull SQLiteDatabase db) {
-        Cursor cursor = null;
-        try {
-            cursor = db.rawQuery("SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name = '"+TABLE_STORAGE+"'", null);
-            if(cursor != null && cursor.getCount() > 0) {
-                return;
-            }
-            db.execSQL(STATEMENT_CREATE_TABLE);
-        }catch (Exception e){
-            e.printStackTrace();
-        }finally {
-            if(cursor != null){
-                cursor.close();
-            }
-        }
-    }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/WXStorageModule.java b/android/sdk/src/main/java/com/taobao/weex/appfram/storage/WXStorageModule.java
deleted file mode 100644
index b6d9534..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/storage/WXStorageModule.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.annotation.JSMethod;
-
-import java.util.Map;
-
-public class WXStorageModule extends WXSDKEngine.DestroyableModule implements IWXStorage {
-
-    IWXStorageAdapter mStorageAdapter;
-
-    private IWXStorageAdapter ability() {
-        if (mStorageAdapter != null) {
-            return mStorageAdapter;
-        }
-        mStorageAdapter = WXSDKEngine.getIWXStorageAdapter();
-        return mStorageAdapter;
-    }
-
-
-    @Override
-    @JSMethod(uiThread = false)
-    public void setItem(String key, String value, @Nullable final JSCallback callback) {
-        if (TextUtils.isEmpty(key) || value == null) {
-            StorageResultHandler.handleInvalidParam(callback);
-            return;
-        }
-
-        IWXStorageAdapter adapter = ability();
-        if (adapter == null) {
-            StorageResultHandler.handleNoHandlerError(callback);
-            return;
-        }
-        adapter.setItem(key, value, new IWXStorageAdapter.OnResultReceivedListener() {
-            @Override
-            public void onReceived(Map<String, Object> data) {
-                if(callback != null){
-                    callback.invoke(data);
-                }
-            }
-        });
-
-
-    }
-
-    @Override
-    @JSMethod(uiThread = false)
-    public void getItem(String key, @Nullable final JSCallback callback) {
-        if (TextUtils.isEmpty(key)) {
-            StorageResultHandler.handleInvalidParam(callback);
-            return;
-        }
-
-        IWXStorageAdapter adapter = ability();
-        if (adapter == null) {
-            StorageResultHandler.handleNoHandlerError(callback);
-            return;
-        }
-        adapter.getItem(key, new IWXStorageAdapter.OnResultReceivedListener() {
-            @Override
-            public void onReceived(Map<String, Object> data) {
-                if(callback != null){
-                    callback.invoke(data);
-                }
-            }
-        });
-    }
-
-    @Override
-    @JSMethod(uiThread = false)
-    public void removeItem(String key, @Nullable final JSCallback callback) {
-        if (TextUtils.isEmpty(key)) {
-            StorageResultHandler.handleInvalidParam(callback);
-            return;
-        }
-
-        IWXStorageAdapter adapter = ability();
-        if (adapter == null) {
-            StorageResultHandler.handleNoHandlerError(callback);
-            return;
-        }
-        adapter.removeItem(key, new IWXStorageAdapter.OnResultReceivedListener() {
-            @Override
-            public void onReceived(Map<String, Object> data) {
-                if(callback != null){
-                    callback.invoke(data);
-                }
-            }
-        });
-    }
-
-    @Override
-    @JSMethod(uiThread = false)
-    public void length(@Nullable final JSCallback callback) {
-        IWXStorageAdapter adapter = ability();
-        if (adapter == null) {
-            StorageResultHandler.handleNoHandlerError(callback);
-            return;
-        }
-        adapter.length(new IWXStorageAdapter.OnResultReceivedListener() {
-            @Override
-            public void onReceived(Map<String, Object> data) {
-                if(callback != null){
-                    callback.invoke(data);
-                }
-            }
-        });
-    }
-
-    @Override
-    @JSMethod(uiThread = false)
-    public void getAllKeys(@Nullable final JSCallback callback) {
-        IWXStorageAdapter adapter = ability();
-        if (adapter == null) {
-            StorageResultHandler.handleNoHandlerError(callback);
-            return;
-        }
-        adapter.getAllKeys(new IWXStorageAdapter.OnResultReceivedListener() {
-            @Override
-            public void onReceived(Map<String, Object> data) {
-                if(callback != null){
-                    callback.invoke(data);
-                }
-            }
-        });
-    }
-
-    @Override
-    @JSMethod(uiThread = false)
-    public void setItemPersistent(String key, String value, @Nullable final JSCallback callback) {
-        if (TextUtils.isEmpty(key) || value == null) {
-            StorageResultHandler.handleInvalidParam(callback);
-            return;
-        }
-
-        IWXStorageAdapter adapter = ability();
-        if (adapter == null) {
-            StorageResultHandler.handleNoHandlerError(callback);
-            return;
-        }
-        adapter.setItemPersistent(key, value, new IWXStorageAdapter.OnResultReceivedListener() {
-            @Override
-            public void onReceived(Map<String, Object> data) {
-                if(callback != null){
-                    callback.invoke(data);
-                }
-            }
-        });
-    }
-
-    @Override
-    public void destroy() {
-        IWXStorageAdapter adapter = ability();
-        if (adapter != null) {
-            adapter.close();
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/IWebSocketAdapter.java b/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/IWebSocketAdapter.java
deleted file mode 100644
index aebd1b8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/IWebSocketAdapter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.websocket;
-
-import android.support.annotation.Nullable;
-
-/**
- * Created by moxun on 16/12/27.
- */
-
-public interface IWebSocketAdapter {
-
-    String HEADER_SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
-
-    void connect(String url, @Nullable String protocol, EventListener listener);
-
-    void send(String data);
-
-    void close(int code, String reason);
-
-    void destroy();
-
-    interface EventListener {
-        void onOpen();
-
-        void onMessage(String data);
-
-        void onClose(int code, String reason, boolean wasClean);
-
-        void onError(String msg);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/IWebSocketAdapterFactory.java b/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/IWebSocketAdapterFactory.java
deleted file mode 100644
index e2e21dd..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/IWebSocketAdapterFactory.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.websocket;
-
-/**
- * Created by moxun on 16/12/28.
- */
-
-public interface IWebSocketAdapterFactory {
-    IWebSocketAdapter createWebSocketAdapter();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/WebSocketCloseCodes.java b/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/WebSocketCloseCodes.java
deleted file mode 100644
index 6251399..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/WebSocketCloseCodes.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.websocket;
-
-/**
- * Created by moxun on 17/1/3.
- * @link {https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
- */
-
-public enum WebSocketCloseCodes {
-    CLOSE_NORMAL(1000),
-    CLOSE_GOING_AWAY(1001),
-    CLOSE_PROTOCOL_ERROR(1002),
-    CLOSE_UNSUPPORTED(1003),
-    CLOSE_NO_STATUS(1005),
-    CLOSE_ABNORMAL(1006),
-    UNSUPPORTED_DATA(1007),
-    POLICY_VIOLATION(1008),
-    CLOSE_TOO_LARGE(1009),
-    MISSING_EXTENSION(1010),
-    INTERNAL_ERROR(1011),
-    SERVICE_RESTART(1012),
-    TRY_AGAIN_LATER(1013),
-    TLS_HANDSHAKE(1015);
-
-    private int code;
-
-    WebSocketCloseCodes(int code) {
-        this.code = code;
-    }
-
-    public int getCode() {
-        return code;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/WebSocketModule.java b/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/WebSocketModule.java
deleted file mode 100644
index f05f560..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/appfram/websocket/WebSocketModule.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.websocket;
-
-import android.os.Looper;
-
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by moxun on 16/12/27.
- */
-
-public class WebSocketModule extends WXSDKEngine.DestroyableModule {
-
-    private static final String TAG = "WebSocketModule";
-    private static final String KEY_DATA = "data";
-    private static final String KEY_CODE = "code";
-    private static final String KEY_REASON = "reason";
-    private static final String KEY_WAS_CLEAN = "wasClean";
-
-    private IWebSocketAdapter webSocketAdapter;
-    private WebSocketEventListener eventListener;
-
-    public WebSocketModule() {
-        WXLogUtils.e(TAG, "create new instance");
-    }
-
-    @JSMethod(uiThread = false)
-    public void WebSocket(String url, String protocol) {
-        if (webSocketAdapter != null) {
-            WXLogUtils.w(TAG, "close");
-            webSocketAdapter.close(WebSocketCloseCodes.CLOSE_GOING_AWAY.getCode(), WebSocketCloseCodes.CLOSE_GOING_AWAY.name());
-        }
-        webSocketAdapter = mWXSDKInstance.getWXWebSocketAdapter();
-        if (!reportErrorIfNoAdapter()) {
-            eventListener = new WebSocketEventListener();
-            webSocketAdapter.connect(url, protocol, eventListener);
-        }
-    }
-
-    @JSMethod(uiThread = false)
-    public void send(String data) {
-        if (!reportErrorIfNoAdapter()) {
-            webSocketAdapter.send(data);
-        }
-    }
-
-    @JSMethod(uiThread = false)
-    public void close(String code, String reason) {
-        if (!reportErrorIfNoAdapter()) {
-            int codeNumber = WebSocketCloseCodes.CLOSE_NORMAL.getCode();
-            if (code != null) {
-                try {
-                    codeNumber = Integer.parseInt(code);
-                } catch (NumberFormatException e) {
-                    //ignore
-                }
-            }
-            webSocketAdapter.close(codeNumber, reason);
-        }
-    }
-
-    @JSMethod(uiThread = false)
-    public void onopen(JSCallback callback) {
-        if (eventListener != null) {
-            eventListener.onOpen = callback;
-        }
-    }
-
-    @JSMethod(uiThread = false)
-    public void onmessage(JSCallback callback) {
-        if (eventListener != null) {
-            eventListener.onMessage = callback;
-        }
-    }
-
-    @JSMethod(uiThread = false)
-    public void onclose(JSCallback callback) {
-        if (eventListener != null) {
-            eventListener.onClose = callback;
-        }
-    }
-
-    @JSMethod(uiThread = false)
-    public void onerror(JSCallback callback) {
-        if (eventListener != null) {
-            eventListener.onError = callback;
-        }
-    }
-
-    @Override
-    public void destroy() {
-        Runnable destroyTask = new Runnable() {
-            @Override
-            public void run() {
-                WXLogUtils.w(TAG, "close session with instance id " + mWXSDKInstance.getInstanceId());
-                if (webSocketAdapter != null) {
-                    webSocketAdapter.destroy();
-                }
-                webSocketAdapter = null;
-                eventListener = null;
-            }
-        };
-
-        if (Looper.myLooper() == Looper.getMainLooper()) {
-            WXBridgeManager.getInstance().post(destroyTask);
-        } else {
-            destroyTask.run();
-        }
-    }
-
-    private boolean reportErrorIfNoAdapter() {
-        if (webSocketAdapter == null) {
-            if (eventListener != null) {
-                eventListener.onError("No implementation found for IWebSocketAdapter");
-            }
-            WXLogUtils.e(TAG, "No implementation found for IWebSocketAdapter");
-            return true;
-        }
-        return false;
-    }
-
-    private class WebSocketEventListener implements IWebSocketAdapter.EventListener {
-        private JSCallback onOpen;
-        private JSCallback onClose;
-        private JSCallback onError;
-        private JSCallback onMessage;
-
-        @Override
-        public void onOpen() {
-            if (onOpen != null) {
-                onOpen.invoke(new HashMap<>(0));
-            }
-        }
-
-        @Override
-        public void onMessage(String data) {
-            if (onMessage != null) {
-                Map<String, String> msg = new HashMap<>(1);
-                msg.put(KEY_DATA, data);
-                onMessage.invokeAndKeepAlive(msg);
-            }
-        }
-
-        @Override
-        public void onClose(int code, String reason, boolean wasClean) {
-            if (onClose != null) {
-                Map<String, Object> msg = new HashMap<>(3);
-                msg.put(KEY_CODE, code);
-                msg.put(KEY_REASON, reason);
-                msg.put(KEY_WAS_CLEAN, wasClean);
-                onClose.invoke(msg);
-            }
-        }
-
-        @Override
-        public void onError(String msg) {
-            if (onError != null) {
-                Map<String, String> info = new HashMap<>(1);
-                info.put(KEY_DATA, msg);
-                onError.invokeAndKeepAlive(info);
-            }
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/base/CalledByNative.java b/android/sdk/src/main/java/com/taobao/weex/base/CalledByNative.java
deleted file mode 100644
index 15fa920..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/base/CalledByNative.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.base;
-public @interface CalledByNative {
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/base/FloatUtil.java b/android/sdk/src/main/java/com/taobao/weex/base/FloatUtil.java
deleted file mode 100755
index ecbeeb4..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/base/FloatUtil.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.base;
-
-public class FloatUtil {
-
-  private static final float EPSILON = .00001f;
-
-  public static boolean floatsEqual(float f1, float f2) {
-    if (Float.isNaN(f1) || Float.isNaN(f2)) {
-      return Float.isNaN(f1) && Float.isNaN(f2);
-    }
-    return Math.abs(f2 - f1) < EPSILON;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/base/SystemMessageHandler.java b/android/sdk/src/main/java/com/taobao/weex/base/SystemMessageHandler.java
deleted file mode 100644
index 50ecfa7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/base/SystemMessageHandler.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.base;
-
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-
-public class SystemMessageHandler extends Handler implements Serializable {
-
-    private static final String TAG = "SystemMessageHandler";
-
-    private static final int SCHEDULED_WORK = 1;
-
-    private long mMessagePumpDelegateNative = 0;
-
-    private Method mMessageMethodSetAsynchronous;
-
-    private native void nativeRunWork(long delegateNative);
-
-    private SystemMessageHandler(long messagePumpDelegateNative) {
-        this.mMessagePumpDelegateNative = messagePumpDelegateNative;
-        try {
-            Class<?> messageClass = Class.forName("android.os.Message");
-            mMessageMethodSetAsynchronous = messageClass.getMethod(
-                    "setAsynchronous", new Class[]{boolean.class});
-        } catch (ClassNotFoundException e) {
-            Log.e(TAG, "Failed to find android.os.Message class:" + e);
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
-        } catch (RuntimeException e) {
-            Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
-        }
-    }
-
-    @CalledByNative
-    public static SystemMessageHandler create(long messagePumpDelegateNative) {
-        return new SystemMessageHandler(messagePumpDelegateNative);
-    }
-
-    @CalledByNative
-    private void scheduleWork() {
-        sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
-    }
-
-    @CalledByNative
-    private void scheduleDelayedWork(long delayMillis) {
-        sendMessageDelayed(obtainAsyncMessage(SCHEDULED_WORK), delayMillis);
-    }
-
-    @CalledByNative
-    private void stop() {
-        removeMessages(SCHEDULED_WORK);
-    }
-
-    private Message obtainAsyncMessage(int what) {
-        Message msg = Message.obtain();
-        msg.what = what;
-//        if (mMessageMethodSetAsynchronous != null) {
-//            // If invocation fails, assume this is indicative of future
-//            // failures, and avoid log spam by nulling the reflected method.
-//            try {
-//                mMessageMethodSetAsynchronous.invoke(msg, true);
-//            } catch (IllegalAccessException e) {
-//                Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
-//                mMessageMethodSetAsynchronous = null;
-//            } catch (IllegalArgumentException e) {
-//                Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
-//                mMessageMethodSetAsynchronous = null;
-//            } catch (InvocationTargetException e) {
-//                Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
-//                mMessageMethodSetAsynchronous = null;
-//            } catch (RuntimeException e) {
-//                Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
-//                mMessageMethodSetAsynchronous = null;
-//            }
-//        }
-        return msg;
-    }
-
-    @Override
-    public void handleMessage(Message msg) {
-        nativeRunWork(mMessagePumpDelegateNative);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/EventResult.java b/android/sdk/src/main/java/com/taobao/weex/bridge/EventResult.java
deleted file mode 100644
index 5d0e82d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/EventResult.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-/**
- * Created by furture on 2017/10/17.
- */
-
-public class EventResult {
-
-    private Object result;
-    private boolean success = false;
-    /**
-     * onCallback javascript event callback method
-     * @param result
-     */
-    public void onCallback(Object result){
-        this.success = true;
-        this.result = result;
-    }
-
-    public boolean isSuccess() {
-        return success;
-    }
-
-    public Object getResult(){
-        return  result;
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/Invoker.java b/android/sdk/src/main/java/com/taobao/weex/bridge/Invoker.java
deleted file mode 100644
index 43eab76..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/Invoker.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Type;
-
-/**
- * Created by sospartan on 6/16/16.
- */
-public interface Invoker {
-  Object invoke(Object receiver,Object...params) throws InvocationTargetException, IllegalAccessException;
-
-  Type[] getParameterTypes();
-
-  boolean isRunOnUIThread();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/JSCallback.java b/android/sdk/src/main/java/com/taobao/weex/bridge/JSCallback.java
deleted file mode 100644
index d0ccb69..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/JSCallback.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-/**
- * Created by sospartan on 5/24/16.
- */
-public interface JSCallback {
-  /**
-   * invoke javascript callback method, this method will destoryed after invoke.
-   * @param data
-   */
-  void invoke(Object data);
-
-  /**
-   * invoke javascript callback method and keep callback alive for later use.
-   * @param data
-   */
-  void invokeAndKeepAlive(Object data);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/JavascriptInvokable.java b/android/sdk/src/main/java/com/taobao/weex/bridge/JavascriptInvokable.java
deleted file mode 100644
index 32afe62..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/JavascriptInvokable.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-/**
- * Created by sospartan on 11/11/2016.
- */
-
-public interface JavascriptInvokable {
-  String[] getMethods();
-  Invoker getMethodInvoker(String name);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/MethodInvoker.java b/android/sdk/src/main/java/com/taobao/weex/bridge/MethodInvoker.java
deleted file mode 100644
index 740e081..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/MethodInvoker.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-
-/**
- * Created by sospartan on 6/16/16.
- */
-public class MethodInvoker implements Invoker {
-
-  final Method mMethod;
-  final boolean mRunOnUIThread;
-  Type[] mParam;
-
-  public MethodInvoker(Method method){
-    this(method,false);
-  }
-
-  public MethodInvoker(Method method,boolean runInUIThread){
-    mMethod = method;
-    mParam = mMethod.getGenericParameterTypes();
-    mRunOnUIThread = runInUIThread;
-  }
-
-  @Override
-  public Object invoke(Object receiver, Object... params) throws InvocationTargetException, IllegalAccessException {
-    return mMethod.invoke(receiver,params);
-  }
-
-  @Override
-  public Type[] getParameterTypes() {
-    if(mParam ==null){
-      mParam = mMethod.getGenericParameterTypes();
-    }
-    return mParam;
-  }
-
-  @Override
-  public boolean isRunOnUIThread() {
-    return mRunOnUIThread;
-  }
-
-  @Override
-  public String toString() {
-    return mMethod.getName();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/ModuleFactory.java b/android/sdk/src/main/java/com/taobao/weex/bridge/ModuleFactory.java
deleted file mode 100644
index a5b41db..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/ModuleFactory.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.taobao.weex.common.WXModule;
-
-import java.util.ArrayList;
-import java.util.Map;
-
-/**
- * Created by sospartan on 6/17/16.
- */
-public interface ModuleFactory<T extends WXModule> extends JavascriptInvokable {
-
-  T buildInstance() throws IllegalAccessException, InstantiationException;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/ModuleFactoryImpl.java b/android/sdk/src/main/java/com/taobao/weex/bridge/ModuleFactoryImpl.java
deleted file mode 100644
index da26f14..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/ModuleFactoryImpl.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-/**
- * Created by shiwentao on 2018/3/13.
- */
-
-public class ModuleFactoryImpl {
-  public ModuleFactory mFactory = null;
-  public boolean hasRigster = false;
-
-  public ModuleFactoryImpl(ModuleFactory factory) {
-    mFactory = factory;
-  }
-
-  public ModuleFactoryImpl(ModuleFactory factory, boolean rigister) {
-    mFactory = factory;
-    hasRigster = rigister;
-  }
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java b/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java
deleted file mode 100644
index a84a240..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import android.util.Log;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.performance.WXAnalyzerDataTransfer;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXReflectionUtils;
-
-import java.lang.reflect.Type;
-
-/**
- * Created by sospartan on 10/11/2016.
- */
-
-public class NativeInvokeHelper {
-  private String mInstanceId;
-
-  public NativeInvokeHelper(String instanceId){
-    mInstanceId = instanceId;
-  }
-
-  public Object invoke(final Object target,final Invoker invoker,JSONArray args) throws Exception {
-    final Object[] params = prepareArguments(
-            invoker.getParameterTypes(),
-            args);
-
-    if (WXAnalyzerDataTransfer.isInteractionLogOpen() && invoker instanceof MethodInvoker) {
-      for (int i = 0; i < params.length; i++) {
-        if (params[i] instanceof SimpleJSCallback) {
-          final String callBackId = ((SimpleJSCallback)params[i]).getCallbackId();
-          Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][callNativeModuleStart]," + mInstanceId + "," + ((MethodInvoker) invoker).mMethod.getDeclaringClass() + "," + ((MethodInvoker) invoker).mMethod.getName() + "," + callBackId);
-          ((SimpleJSCallback) params[i]).setInvokerCallback(new SimpleJSCallback.InvokerCallback() {
-            @Override
-            public void onInvokeSuccess() {
-              Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][callNativeModuleEnd]," + mInstanceId + "," + ((MethodInvoker) invoker).mMethod.getDeclaringClass() + "," + ((MethodInvoker) invoker).mMethod.getName() + "," + callBackId);
-            }
-          });
-          break;
-        }
-      }
-    }
-
-    if (invoker.isRunOnUIThread()) {
-      WXSDKManager.getInstance().postOnUiThread(new Runnable() {
-        @Override
-        public void run() {
-          if (invoker != null) {
-            try {
-              WXSDKInstance targetInstance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
-              if (null == targetInstance || targetInstance.isDestroy()){
-                return;
-              }
-              invoker.invoke(target, params);
-            } catch (Exception e) {
-              WXLogUtils.e("NativeInvokeHelper",target + " Invoker " + invoker.toString()+" exception:"+e);
-            }
-          }
-        }
-      }, 0);
-    } else {
-      return invoker.invoke(target, params);
-    }
-    return null;
-  }
-
-  protected Object[] prepareArguments(Type[] paramClazzs, JSONArray args) throws Exception {
-    Object[] params = new Object[paramClazzs.length];
-    Object value;
-    Type paramClazz;
-    for (int i = 0; i < paramClazzs.length; i++) {
-      paramClazz = paramClazzs[i];
-      if(i>=args.size()){
-        if(!paramClazz.getClass().isPrimitive()) {
-          params[i] = null;
-          continue;
-        }else {
-          throw new Exception("[prepareArguments] method argument list not match.");
-        }
-      }
-      value = args.get(i);
-
-      if (paramClazz == JSONObject.class) {
-        if(value instanceof  JSONObject || value == null) {
-          params[i] = value;
-        }else if (value instanceof String){
-          params[i] = JSON.parseObject(value.toString());
-        }
-      } else if(JSCallback.class == paramClazz){
-        if(value instanceof String){
-          params[i] = new SimpleJSCallback(mInstanceId,(String)value);
-        }else{
-          throw new Exception("Parameter type not match.");
-        }
-      } else {
-        params[i] = WXReflectionUtils.parseArgument(paramClazz,value);
-      }
-    }
-    return params;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/RequestHandler.java b/android/sdk/src/main/java/com/taobao/weex/bridge/RequestHandler.java
deleted file mode 100644
index f49ba9c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/RequestHandler.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT;
-
-import android.net.Uri;
-import android.support.annotation.Keep;
-import android.text.TextUtils;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXHttpListener;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.base.CalledByNative;
-import com.taobao.weex.bridge.WXBridgeManager.BundType;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.common.WXResponse;
-import com.taobao.weex.http.WXHttpUtil;
-import com.taobao.weex.utils.WXExceptionUtils;
-
-import com.taobao.weex.utils.WXLogUtils;
-import java.util.HashMap;
-import java.util.Locale;
-
-public class RequestHandler {
-
-  @Keep
-  native void nativeInvokeOnSuccess(long callback, String script, String bundleType);
-  native void nativeInvokeOnFailed(long callback);
-
-  @CalledByNative
-  public static RequestHandler create() {
-    return new RequestHandler();
-  }
-
-  @CalledByNative
-  public void send(String instanceId, String url, long nativeCallback) {
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(url) ||
-        nativeCallback == 0 ||
-        !WXSDKManager.getInstance().getAllInstanceMap().containsKey(
-            instanceId)) {
-      return;
-    }
-
-    WXSDKManager manager = WXSDKManager.getInstance();
-    WXSDKInstance instance =
-        WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance == null)
-      return;
-    IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter();
-
-    WXRequest wxRequest = new WXRequest();
-    wxRequest.url = manager.getURIAdapter()
-                        .rewrite(instance, URIAdapter.BUNDLE, Uri.parse(url))
-                        .toString();
-
-    if (wxRequest.paramMap == null) {
-      wxRequest.paramMap = new HashMap<>();
-    }
-    wxRequest.paramMap.put(
-        KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(
-                            instance.getContext(), WXEnvironment.getConfig()));
-    wxRequest.paramMap.put("isBundleRequest", "true");
-    WXLogUtils.i("Eagle", String.format(Locale.ENGLISH, "Weex eagle is going to download script from %s", url));
-    adapter.sendRequest(wxRequest, new OnHttpListenerInner(instance, nativeCallback, url));
-  }
-
-  @Keep
-  @CalledByNative
-  public void getBundleType(String instanceId, final String content, final long nativeCallback){
-    BundType bundleType = WXBridgeManager.getInstance().getBundleType("", content);
-    final String bundleTypeStr = bundleType == null ? "Others" : bundleType.toString();
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if ("Others".equalsIgnoreCase(bundleTypeStr) && null != instance){
-      WXExceptionUtils.commitCriticalExceptionRT(
-          instanceId,
-          WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE,
-          "RequestHandler.onSuccess",
-          "eagle ->" +WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE.getErrorMsg(),
-          null
-      );
-    }
-    WXBridgeManager.getInstance().post(new Runnable() {
-      @Override
-      public void run() {
-        if(WXBridgeManager.getInstance().isJSFrameworkInit()) {
-          nativeInvokeOnSuccess(nativeCallback, content, bundleTypeStr);
-        }
-        else {
-          nativeInvokeOnFailed(nativeCallback);
-        }
-      }
-    });
-  }
-
-  class OnHttpListenerInner extends WXHttpListener {
-    private long sNativeCallback;
-
-    OnHttpListenerInner(WXSDKInstance instance, long nativeCallback, String bundlUrl) {
-      super(instance, bundlUrl);
-      sNativeCallback = nativeCallback;
-    }
-
-    @Override
-    public void onSuccess(WXResponse response) {
-        final String script = new String(response.originalData);
-        BundType bundleType = WXBridgeManager.getInstance().getBundleType("", script);
-        final String bundleTypeStr = bundleType == null ? "Others" : bundleType.toString();
-        if ("Others".equalsIgnoreCase(bundleTypeStr) && null != getInstance()){
-          WXExceptionUtils.commitCriticalExceptionRT(
-              getInstance().getInstanceId(),
-              WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE,
-              "RequestHandler.onSuccess",
-              "eagle ->" +WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE.getErrorMsg(),
-              null
-          );
-        }
-        WXBridgeManager.getInstance().post(new Runnable() {
-          @Override
-          public void run() {
-            if(WXBridgeManager.getInstance().isJSFrameworkInit()) {
-              nativeInvokeOnSuccess(sNativeCallback, script, bundleTypeStr);
-            }
-            else{
-              nativeInvokeOnFailed(sNativeCallback);
-            }
-          }
-        });
-    }
-
-    @Override
-    public void onFail(WXResponse response) {
-      nativeInvokeOnFailed(sNativeCallback);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/ResultCallback.java b/android/sdk/src/main/java/com/taobao/weex/bridge/ResultCallback.java
deleted file mode 100644
index 368a5b1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/ResultCallback.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-public interface ResultCallback<T> {
-    void onReceiveResult(T result);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/ResultCallbackManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/ResultCallbackManager.java
deleted file mode 100644
index 59475be..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/ResultCallbackManager.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import android.util.SparseArray;
-
-/**
- * Manage async callbacks which waiting for the result of executing javascript
- */
-/* default */ class ResultCallbackManager {
-    // Unique id for callback after executing js
-    private static long sCallbackId = 0;
-    // Map for save callbacks, key is id
-    private static SparseArray<ResultCallback> mResultCallbacks = new SparseArray<>();
-
-    // Generate unique id
-    static long generateCallbackId(ResultCallback callback) {
-        if (sCallbackId >= Integer.MAX_VALUE) {
-            sCallbackId = 0;
-        }
-        int id = (int) sCallbackId++;
-        mResultCallbacks.put(id, callback);
-        return id;
-    }
-
-    // Remove id from callback map
-    static ResultCallback removeCallbackById(long id) {
-        ResultCallback callback = mResultCallbacks.get((int) id);
-        mResultCallbacks.remove((int) id);
-        return callback;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/SimpleJSCallback.java b/android/sdk/src/main/java/com/taobao/weex/bridge/SimpleJSCallback.java
deleted file mode 100644
index 8b9411e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/SimpleJSCallback.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-/**
- * Created by sospartan on 27/10/2016.
- */
-public class SimpleJSCallback implements JSCallback {
-
-  String mInstanceId;
-  String mCallbackId;
-
-  private InvokerCallback mInvokerCallback;
-
-  public void setInvokerCallback(InvokerCallback callback) {
-    this.mInvokerCallback = callback;
-  }
-
-  interface InvokerCallback {
-    void onInvokeSuccess();
-  }
-
-  public String getCallbackId() {
-    return mCallbackId;
-  }
-
-  public SimpleJSCallback(String instanceId, String callbackId) {
-    this.mCallbackId = callbackId;
-    this.mInstanceId = instanceId;
-  }
-
-
-  @Override
-  public void invoke(Object data) {
-    WXBridgeManager.getInstance().callbackJavascript(mInstanceId, mCallbackId, data, false);
-    if (mInvokerCallback != null) {
-      mInvokerCallback.onInvokeSuccess();
-    }
-  }
-
-  @Override
-  public void invokeAndKeepAlive(Object data) {
-    WXBridgeManager.getInstance().callbackJavascript(mInstanceId, mCallbackId, data, true);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridge.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridge.java
deleted file mode 100755
index 14181c1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridge.java
+++ /dev/null
@@ -1,936 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.base.CalledByNative;
-import com.taobao.weex.common.IWXBridge;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.performance.WXStateRecord;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXJsonUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXWsonJSONSwitch;
-import com.taobao.weex.utils.tools.TimeCalculator;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-
-/**
- * Communication interface for Java code and JavaScript code.
- */
-
-    public class WXBridge implements IWXBridge {
-
-  private native int nativeInitFrameworkEnv(String framework, WXParams params, String cacheDir, boolean pieSupport);
-
-  private native int nativeInitFramework(String framework, WXParams params);
-
-  private native void nativeRefreshInstance(String instanceId, String namespace, String function, WXJSObject[] args);
-
-  private native int nativeExecJS(String instanceId, String name, String function, WXJSObject[] args);
-
-  private native int nativeExecJSService(String javascript);
-
-  public native byte[] nativeExecJSWithResult(String instanceId, String _namespace, String _function, WXJSObject[] args);
-  public native void nativeExecJSWithCallback(String instanceId, String _namespace, String _function, WXJSObject[] args, long callbackId);
-
-  public native int nativeCreateInstanceContext(String instanceId, String name, String function, WXJSObject[] args);
-
-  public native int nativeDestoryInstance(String instanceId, String name, String function, WXJSObject[] args);
-
-  public native String nativeExecJSOnInstance(String instanceId, String script, int type);
-
-  public native void nativeFireEventOnDataRenderNode(String instanceId, String ref, String type, String data, String domChanges);
-
-  public native void nativeInvokeCallbackOnDataRender(String instanceId, String callbackId, String data, boolean keepAlive);
-
-  public native void nativeRegisterModuleOnDataRenderNode( String data);
-
-  public native void nativeRegisterComponentOnDataRenderNode( String data);
-
-  private native void nativeTakeHeapSnapshot(String filename);
-
-  private native void nativeBindMeasurementToRenderObject(long ptr);
-
-  private native void nativeSetRenderContainerWrapContent(boolean wrap, String instanceId);
-
-  public native long[] nativeGetFirstScreenRenderTime(String instanceId);
-
-  public native long[] nativeGetRenderFinishTime(String instanceId);
-
-  private native void nativeSetDefaultHeightAndWidthIntoRootDom(String instanceId, float defaultWidth, float defaultHeight, boolean isWidthWrapContent, boolean isHeightWrapContent);
-
-  private native void nativeOnInstanceClose(String instanceId);
-
-  private native void nativeForceLayout(String instanceId);
-
-  private native boolean nativeNotifyLayout(String instanceId);
-
-  private native void nativeSetStyleWidth(String instanceId, String ref, float value);
-
-  private native void nativeSetStyleHeight(String instanceId, String ref, float value);
-
-  private native void nativeSetMargin(String instanceId, String ref, int edge, float value);
-
-  private native void nativeSetPadding(String instanceId, String ref, int edge, float value);
-
-  private native void nativeSetPosition(String instanceId, String ref, int edge, float value);
-
-  private native void nativeMarkDirty(String instanceId, String ref, boolean dirty);
-
-  private native void nativeSetDeviceDisplay(String instanceId, float width, float height, float scale);
-
-  private native void nativeRegisterCoreEnv(String key, String value);
-
-  private native void nativeResetWXBridge(Object bridge, String className);
-
-  private native void nativeSetInstanceRenderType(String instanceId, String renderType);
-
-  private native void nativeRemoveInstanceRenderType(String instanceId);
-
-  private native void nativeSetPageArgument(String instanceId, String key, String value);
-
-  public native void nativeOnInteractionTimeUpdate(String instanceId);
-
-  public native String nativeDumpIpcPageQueueInfo();
-
-  /**
-   * Update Init Framework Params
-   * */
-  private native void nativeUpdateInitFrameworkParams(String key, String value, String desc);
-
-  /**
-   * update global config,
-   * @param config params
-   * */
-  public native void nativeUpdateGlobalConfig(String config);
-
-  private native void nativeSetViewPortWidth(String instanceId, float viewPortWidth);
-  private native void nativeSetLogType(float type, float isPerf);
-
-  private native void nativeReloadPageLayout(String instanceId);
-
-  private native void nativeSetDeviceDisplayOfPage(String instanceId,float width,float height);
-
-  public static final boolean MULTIPROCESS = true;
-
-
-  @Override
-  public void updateInitFrameworkParams(String key, String value, String desc){
-    WXStateRecord.getInstance().recordAction("","updateInitFrameworkParams:");
-     nativeUpdateInitFrameworkParams(key, value, desc);
-  }
-
-  @Override
-  public void setLogType(float type, boolean isPerf) {
-    Log.e("WeexCore", "setLog" + WXEnvironment.sLogLevel.getValue() + "isPerf : " + isPerf);
-    nativeSetLogType(type, isPerf ? 1 : 0);
-  }
-
-  @Override
-  public int initFramework(String framework, WXParams params) {
-    return nativeInitFramework(framework, params);
-  }
-
-  @Override
-  public int initFrameworkEnv(String framework, WXParams params, String cacheDir, boolean pieSupport) {
-    if (MULTIPROCESS) {
-      WXStateRecord.getInstance().recordAction("","nativeInitFrameworkEnv:");
-      return nativeInitFrameworkEnv(framework, params, cacheDir, pieSupport);
-    } else {
-      WXStateRecord.getInstance().recordAction("","nativeInitFramework:");
-      return nativeInitFramework(framework, params);
-    }
-  }
-
-  @Override
-  public void refreshInstance(String instanceId, String namespace, String function, WXJSObject[] args) {
-    WXStateRecord.getInstance().recordAction(instanceId,"refreshInstance:"+namespace+","+function);
-    nativeRefreshInstance(instanceId, namespace, function, args);
-  }
-
-  @Override
-  public int execJS(String instanceId, String namespace, String function, WXJSObject[] args) {
-    WXStateRecord.getInstance().recordAction(instanceId,"execJS:"+namespace+","+function);
-    return nativeExecJS(instanceId, namespace, function, args);
-  }
-
-  @Override
-  public void execJSWithCallback(String instanceId, String namespace, String function, WXJSObject[] args, ResultCallback callback) {
-    WXStateRecord.getInstance().recordAction(instanceId,"execJSWithCallback:"+namespace+","+function);
-    if (callback == null) {
-      execJS(instanceId, namespace, function, args);
-    }
-    nativeExecJSWithCallback(instanceId, namespace, function, args,
-            ResultCallbackManager.generateCallbackId(callback));
-  }
-
-  @CalledByNative
-  public void onNativePerformanceDataUpdate(String instanceId,Map<String,String> map){
-    if (TextUtils.isEmpty(instanceId) || null == map || map.size() < 1){
-      return;
-    }
-    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-    if (null == instance || null == instance.getApmForInstance()){
-      return;
-    }
-    instance.getApmForInstance().updateNativePerformanceData(map);
-  }
-
-  // Result from js engine
-  @CalledByNative
-  public void onReceivedResult(long callbackId, byte[] result) {
-    WXStateRecord.getInstance().recordAction("onReceivedResult","callbackId"+callbackId);
-    ResultCallback callback = ResultCallbackManager.removeCallbackById(callbackId);
-    if (callback != null) {
-       callback.onReceiveResult(result);
-    }
-  }
-
-  @Override
-  public int execJSService(String javascript) {
-    WXStateRecord.getInstance().recordAction("execJSService","execJSService:");
-    return nativeExecJSService(javascript);
-  }
-
-
-  @Override
-  public void takeHeapSnapshot(String filename) {
-    nativeTakeHeapSnapshot(filename);
-  }
-
-  @Override
-  public int createInstanceContext(String instanceId, String name, String function, WXJSObject[] args) {
-    Log.e(TimeCalculator.TIMELINE_TAG,"createInstance :" + System.currentTimeMillis());
-    WXStateRecord.getInstance().recordAction(instanceId,"createInstanceContext:");
-    return nativeCreateInstanceContext(instanceId, name, function, args);
-  }
-
-  @Override
-  public int destoryInstance(String instanceId, String name, String function, WXJSObject[] args) {
-    WXStateRecord.getInstance().recordAction(instanceId,"destoryInstance:");
-    return nativeDestoryInstance(instanceId, name, function, args);
-  }
-
-  @Override
-  public String execJSOnInstance(String instanceId, String script, int type) {
-    WXStateRecord.getInstance().recordAction(instanceId,"execJSOnInstance:"+type);
-    return nativeExecJSOnInstance(instanceId, script, type);
-  }
-
-  public static final String TAG = "WXBridge";
-
-  /**
-   * JavaScript uses this methods to call Android code
-   *
-   * @param instanceId
-   * @param tasks
-   * @param callback
-   */
-  @CalledByNative
-  public int callNative(String instanceId, byte[] tasks, String callback) {
-    if("HeartBeat".equals(callback)) {
-      Log.e("HeartBeat instanceId", instanceId);
-      WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if(sdkInstance != null) {
-        sdkInstance.createInstanceFuncHeartBeat();
-      }
-      return IWXBridge.INSTANCE_RENDERING;
-    }
-
-    return callNative(instanceId, (JSONArray) JSON.parseArray(new String(tasks)), callback);
-  }
-
-  @Override
-  public int callNative(String instanceId, String tasks, String callback) {
-    try{
-      return callNative(instanceId, JSONArray.parseArray(tasks), callback);
-    }catch (Exception e){
-      WXLogUtils.e(TAG, "callNative throw exception: " + WXLogUtils.getStackTrace(e));
-      return IWXBridge.INSTANCE_RENDERING;
-    }
-  }
-
-  private int callNative(String instanceId, JSONArray tasks, String callback){
-    long start = System.currentTimeMillis();
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance != null) {
-      instance.firstScreenCreateInstanceTime(start);
-    }
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callNative(instanceId, tasks, callback);
-    } catch (Throwable e) {
-      WXLogUtils.e(TAG, "callNative throw exception:" + WXLogUtils.getStackTrace(e));
-    }
-
-    if (WXEnvironment.isApkDebugable()) {
-      if (errorCode == IWXBridge.DESTROY_INSTANCE) {
-        WXLogUtils.w("destroyInstance :" + instanceId + " JSF must stop callNative");
-      }
-    }
-    return errorCode;
-  }
-
-  @CalledByNative
-  public void reportJSException(String instanceId, String func, String exception) {
-    WXBridgeManager.getInstance().reportJSException(instanceId, func, exception);
-  }
-
-
-  /**
-   * Bridge module Js Method
-   * support Sync or Async through setting  Annotation as {@link com.taobao.weex.annotation.JSMethod }
-   *
-   * @param instanceId Instance ID
-   * @param module     the name of module
-   * @param method     the name of method
-   * @param arguments  the arguments of the method
-   * @param options    option arguments for extending
-   * @return the result
-   */
-  @Override
-  @CalledByNative
-  public Object callNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options) {
-    try {
-      WXStateRecord.getInstance().recordAction(instanceId,"callNativeModule:"+module+"."+method);
-      long start = WXUtils.getFixUnixTime();
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      JSONArray argArray = null;
-      if (arguments != null){
-        // TODO use a better way
-        if (instance!=null && (instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER
-                || instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER_BINARY)){
-          try {
-            argArray = (JSONArray) JSON.parse(new String(arguments, "UTF-8"));
-          } catch (Exception e) {
-            // For wson use in data render mode
-            argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
-          }
-        } else {
-          argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
-        }
-      }
-      JSONObject optionsObj = null;
-      if (options != null) {
-        optionsObj = (JSONObject) WXWsonJSONSwitch.parseWsonOrJSON(options);
-      } else if (argArray != null) {
-        final WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-        if (sdkInstance != null) {
-          if (WXBridgeManager.BundType.Rax.equals(sdkInstance.bundleType)) {
-            Object weex_options__ = null;
-            for (Object object: argArray) {
-              if (object instanceof JSONObject && ((JSONObject) object).containsKey("__weex_options__")) {
-                weex_options__ = ((JSONObject) object).get("__weex_options__");
-              }
-            }
-
-            if (weex_options__ instanceof JSONObject)
-              optionsObj = (JSONObject) weex_options__;
-          }
-        }
-
-      }
-
-      Object object = WXBridgeManager.getInstance().callNativeModule(instanceId, module, method, argArray, optionsObj);
-
-      if (null != instance){
-        instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_NATIVE_NUM,1);
-        instance.getApmForInstance().updateFSDiffStats(
-            WXInstanceApm.KEY_PAGE_STATS_FS_CALL_NATIVE_TIME,
-            WXUtils.getFixUnixTime()-start
-        );
-      }
-      if (instance!=null && (instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER
-          || instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER_BINARY)){
-        try {
-          if(object == null){
-            return new WXJSObject(null);
-          }
-          if(object.getClass() == WXJSObject.class){
-            return (WXJSObject) object;
-          }
-          return new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(object));
-        } catch (Exception e) {
-          // For wson use in data render mode
-          return WXWsonJSONSwitch.toWsonOrJsonWXJSObject(object);
-        }
-      } else {
-        return WXWsonJSONSwitch.toWsonOrJsonWXJSObject(object);
-      }
-    }catch (Exception e){
-      WXLogUtils.e(TAG,  e);
-      return new WXJSObject(null);
-    }
-  }
-
-  /**
-   * Bridge component Js Method
-   *
-   * @param instanceId   Instance ID
-   * @param ref the ref of component
-   * @param method       the name of method
-   * @param arguments    the arguments of the method
-   * @param options      option arguments for extending
-   */
-  @Override
-  @CalledByNative
-  public void callNativeComponent(String instanceId, String ref, String method, byte[] arguments, byte[] optionsData) {
-    WXStateRecord.getInstance().recordAction(instanceId,"callNativeComponent:"+method);
-    try{
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      JSONArray argArray = null;
-      if (arguments != null){
-        // TODO use a better way
-        if (instance!=null && (instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER
-            || instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER_BINARY)){
-          try {
-            argArray = (JSONArray) JSON.parse(new String(arguments, "UTF-8"));
-          } catch (Exception e) {
-            // For wson use in data render mode
-            argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
-          }
-        } else {
-          argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
-        }
-      }
-      Object options = WXWsonJSONSwitch.parseWsonOrJSON(optionsData);
-      WXBridgeManager.getInstance().callNativeComponent(instanceId, ref, method, argArray, options);
-    }catch (Exception e){
-      WXLogUtils.e(TAG,  e);
-    }
-  }
-
-  @Override
-  @CalledByNative
-  public void setTimeoutNative(String callbackId, String time) {
-    WXBridgeManager.getInstance().setTimeout(callbackId, time);
-  }
-
-  @Override
-  @CalledByNative
-  public void setJSFrmVersion(String version) {
-    if (version != null) {
-      WXEnvironment.JS_LIB_SDK_VERSION = version;
-    }
-    WXStateRecord.getInstance().onJSFMInit();
-  }
-
-  @Override
-  public void resetWXBridge(boolean remoteDebug) {
-    final String className = this.getClass().getName().replace('.', '/');
-    nativeResetWXBridge(this, className);
-  }
-
-  @Override
-  @CalledByNative
-  public int callUpdateFinish(String instanceId, byte[] tasks, String callback) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callUpdateFinish(instanceId, callback);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callCreateBody throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callRefreshFinish(String instanceId, byte[] tasks, String callback) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callRefreshFinish(instanceId, callback);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public void reportServerCrash(String instanceId, String crashFile) {
-    WXLogUtils.e(TAG, "reportServerCrash instanceId:" + instanceId + " crashFile: " + crashFile);
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callReportCrashReloadPage(instanceId, crashFile);
-
-      // upload crash log
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "reloadPageNative throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-  }
-
-  @Override
-  @CalledByNative
-  public int callCreateBody(String instanceId, String componentType, String ref,
-                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
-                            float[] margins, float[] paddings, float[] borders) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-
-    try {
-      errorCode = WXBridgeManager.getInstance().callCreateBody(instanceId, componentType, ref,
-              styles, attributes, events, margins, paddings, borders);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callCreateBody throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callAddElement(String instanceId, String componentType, String ref, int index, String parentRef,
-                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
-                            float[] margins, float[] paddings, float[] borders,  boolean willLayout) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-
-    try {
-      errorCode = WXBridgeManager.getInstance().callAddElement(instanceId, componentType, ref, index, parentRef,
-              styles, attributes, events, margins, paddings, borders, willLayout);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        e.printStackTrace();
-        WXLogUtils.e(TAG, "callAddElement throw error:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callRemoveElement(String instanceId, String ref) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callRemoveElement(instanceId, ref);
-    } catch (Throwable e) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callRemoveElement throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callMoveElement(String instanceId, String ref, String parentref, int index) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callMoveElement(instanceId, ref, parentref, index);
-    } catch (Throwable e) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callMoveElement throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callAddEvent(String instanceId, String ref, String event) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callAddEvent(instanceId, ref, event);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      // if(WXEnvironment.isApkDebugable()){
-      WXLogUtils.e(TAG, "callAddEvent throw exception:" + WXLogUtils.getStackTrace(e));
-      // }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callRemoveEvent(String instanceId, String ref, String event) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callRemoveEvent(instanceId, ref, event);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callRemoveEvent throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callUpdateStyle(String instanceId, String ref,
-                             HashMap<String, Object> styles,
-                             HashMap<String, String> paddings,
-                             HashMap<String, String> margins,
-                             HashMap<String, String> borders) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callUpdateStyle(instanceId, ref, styles, paddings, margins, borders);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callUpdateStyle throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callUpdateAttrs(String instanceId, String ref, HashMap<String, String> attrs) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callUpdateAttrs(instanceId, ref, attrs);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callUpdateAttr throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callAddChildToRichtext(String instanceId, String nodeType, String ref, String parentRef, String richTextRef,
-                             HashMap<String, String> styles, HashMap<String, String> attrs){
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callAddChildToRichtext(instanceId, nodeType, ref, parentRef, richTextRef,
-              styles, attrs);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callAddChildToRichtext throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-  @Override
-  @CalledByNative
-  public int callRemoveChildFromRichtext(String instanceId, String ref, String parentRef, String richTextRef){
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callRemoveChildFromRichtext(instanceId, ref, parentRef, richTextRef);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callRemoveChildFromRichtext throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callUpdateRichtextStyle(String instanceId, String ref, HashMap<String, String> styles, String parentRef, String richTextRef){
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callUpdateRichtextStyle(instanceId, ref, styles, parentRef, richTextRef);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callUpdateRichtextStyle throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-  @Override
-  @CalledByNative
-  public int callUpdateRichtextChildAttr(String instanceId, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef){
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callUpdateRichtextChildAttr(instanceId, ref, attrs, parentRef, richTextRef);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callUpdateRichtextChildAttr throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-
-  @Override
-  @CalledByNative
-  public int callLayout(String instanceId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callLayout(instanceId, ref, top, bottom, left, right, height, width, isRTL, index);
-    } catch (Throwable e) {
-      //catch everything during call native.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callLayout throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callCreateFinish(String instanceId) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callCreateFinish(instanceId);
-    } catch (Throwable e) {
-      WXLogUtils.e(TAG, "callCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callRenderSuccess(String instanceId) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callRenderSuccess(instanceId);
-    } catch (Throwable e) {
-      WXLogUtils.e(TAG, "callCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callAppendTreeCreateFinish(String instanceId, String ref) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callAppendTreeCreateFinish(instanceId, ref);
-    } catch (Throwable e) {
-      WXLogUtils.e(TAG, "callAppendTreeCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public int callHasTransitionPros(String instanceId, String ref, HashMap<String, String> styles) {
-    int errorCode = IWXBridge.INSTANCE_RENDERING;
-    try {
-      errorCode = WXBridgeManager.getInstance().callHasTransitionPros(instanceId, ref, styles);
-    } catch (Throwable e) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "callHasTransitionPros throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return errorCode;
-  }
-
-  @Override
-  @CalledByNative
-  public ContentBoxMeasurement getMeasurementFunc(String instanceId, long renderObjectPtr) {
-    ContentBoxMeasurement obj = null;
-    try {
-      obj = WXBridgeManager.getInstance().getMeasurementFunc(instanceId, renderObjectPtr);
-    } catch (Throwable e) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(TAG, "getMeasurementFunc throw exception:" + WXLogUtils.getStackTrace(e));
-      }
-    }
-    return obj;
-  }
-
-  @Override
-  public void bindMeasurementToRenderObject(long ptr){
-    nativeBindMeasurementToRenderObject(ptr);
-  }
-
-  @Override
-  public void setRenderContainerWrapContent(boolean wrap, String instanceId) {
-    nativeSetRenderContainerWrapContent(wrap, instanceId);
-  }
-
-  @Override
-  public long[] getFirstScreenRenderTime(String instanceId) {
-    return nativeGetFirstScreenRenderTime(instanceId);
-  }
-
-  @Override
-  public long[] getRenderFinishTime(String instanceId) {
-    return nativeGetRenderFinishTime(instanceId);
-  }
-
-  @Override
-  public void setDefaultHeightAndWidthIntoRootDom(String instanceId, float defaultWidth, float defaultHeight, boolean isWidthWrapContent, boolean isHeightWrapContent) {
-    nativeSetDefaultHeightAndWidthIntoRootDom(instanceId, defaultWidth, defaultHeight, isWidthWrapContent, isHeightWrapContent);
-  }
-
-  @Override
-  public void onInstanceClose(String instanceId) {
-    nativeOnInstanceClose(instanceId);
-  }
-
-  @Override
-  public void forceLayout(String instanceId) {
-    nativeForceLayout(instanceId);
-  }
-
-  @Override
-  public boolean notifyLayout(String instanceId) {
-    return nativeNotifyLayout(instanceId);
-  }
-
-  @Override
-  public void setStyleWidth(String instanceId, String ref, float value) {
-    nativeSetStyleWidth(instanceId, ref, value);
-  }
-
-  @Override
-  public void setMargin(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
-    nativeSetMargin(instanceId, ref, edge.ordinal(), value);
-  }
-
-  @Override
-  public void setPadding(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
-    nativeSetPadding(instanceId, ref, edge.ordinal(), value);
-  }
-
-  @Override
-  public void setPosition(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
-    nativeSetPosition(instanceId, ref, edge.ordinal(), value);
-  }
-
-  @Override
-  public void markDirty(String instanceId, String ref, boolean dirty) {
-    nativeMarkDirty(instanceId, ref, dirty);
-  }
-
-  @Override
-  public void setDeviceDisplay(String instanceId, float width, float height, float scale) {
-    nativeSetDeviceDisplay(instanceId, width, height, scale);
-  }
-
-  @Override
-  public void setStyleHeight(String instanceId, String ref, float value) {
-    nativeSetStyleHeight(instanceId, ref, value);
-  }
-
-  @Override
-  public void setInstanceRenderType(String instanceId, String renderType){
-    if(TextUtils.isEmpty(renderType)){
-       return;
-    }
-    nativeSetInstanceRenderType(instanceId, renderType);
-  }
-
-  @Override
-  public void setViewPortWidth(String instanceId,float viewPortWidth){
-    nativeSetViewPortWidth(instanceId,viewPortWidth);
-  }
-
-  @Override
-  public void removeInstanceRenderType(String instanceId){
-      nativeRemoveInstanceRenderType(instanceId);
-  }
-
-  @Override
-  public void setPageArgument(String instanceId, String key, String value){
-      nativeSetPageArgument(instanceId, key, value);
-  }
-
-  @Override
-  public void registerCoreEnv(String key, String value) {
-    nativeRegisterCoreEnv(key, value);
-  }
-
-  @CalledByNative
-  public void reportNativeInitStatus(String statusCode, String errorMsg) {
-    if (WXErrorCode.WX_JS_FRAMEWORK_INIT_SINGLE_PROCESS_SUCCESS.getErrorCode().equals(statusCode)
-            || WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED.getErrorCode().equals(statusCode)) {
-      IWXUserTrackAdapter userTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
-      if (userTrackAdapter != null) {
-        Map<String, Serializable> params = new HashMap<>(3);
-        params.put(IWXUserTrackAdapter.MONITOR_ERROR_CODE, statusCode);
-        params.put(IWXUserTrackAdapter.MONITOR_ARG, "InitFrameworkNativeError");
-        params.put(IWXUserTrackAdapter.MONITOR_ERROR_MSG, errorMsg);
-        WXLogUtils.e("reportNativeInitStatus is running and errorCode is " + statusCode + " And errorMsg is " + errorMsg);
-        userTrackAdapter.commit(null, null, IWXUserTrackAdapter.INIT_FRAMEWORK, null, params);
-      }
-
-      return;
-    }
-
-    if (WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL.getErrorCode().equals(statusCode)) {
-      WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL,
-              "WeexProxy::initFromParam()",
-              WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL.getErrorMsg() + ": " + errorMsg,
-              null);
-      return;
-    }
-
-    for (WXErrorCode e : WXErrorCode.values()) {
-      if (e.getErrorType().equals(WXErrorCode.ErrorType.NATIVE_ERROR)
-              && e.getErrorCode().equals(statusCode)) {
-        WXExceptionUtils.commitCriticalExceptionRT(null, e, "initFramework", errorMsg, null);
-        break;
-      }
-    }
-  }
-
-  public void fireEventOnDataRenderNode(String instanceId, String ref, String type, String data, String domChanges) {
-    nativeFireEventOnDataRenderNode(instanceId,ref,type,data, domChanges);
-  }
-
-  public void invokeCallbackOnDataRender(String instanceId, String callbackId, String data, boolean keepAlive) {
-    nativeInvokeCallbackOnDataRender(instanceId,callbackId,data, keepAlive);
-  }
-
-  public void registerModuleOnDataRenderNode(String data) {
-    nativeRegisterModuleOnDataRenderNode(data);
-  }
-
-  public void registerComponentOnDataRenderNode(String data) {
-    nativeRegisterComponentOnDataRenderNode(data);
-  }
-  public void reloadPageLayout(String instanceId){
-    nativeReloadPageLayout(instanceId);
-  }
-
-  public void setDeviceDisplayOfPage(String instanceId, float width, float height){
-    nativeSetDeviceDisplayOfPage(instanceId,width,height);
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
deleted file mode 100755
index 72843a7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
+++ /dev/null
@@ -1,3681 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import static com.taobao.weex.bridge.WXModuleManager.createDomModule;
-
-import android.content.Context;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.Looper;
-import android.os.Message;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.support.annotation.UiThread;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.Script;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.adapter.IWXJSExceptionAdapter;
-import com.taobao.weex.adapter.IWXJsFileLoaderAdapter;
-import com.taobao.weex.adapter.IWXJscProcessManager;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.common.IWXBridge;
-import com.taobao.weex.common.IWXDebugConfig;
-import com.taobao.weex.common.WXConfig;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXException;
-import com.taobao.weex.common.WXJSBridgeMsgType;
-import com.taobao.weex.common.WXJSExceptionInfo;
-import com.taobao.weex.common.WXRefreshData;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.performance.WXStateRecord;
-import com.taobao.weex.ui.WXComponentRegistry;
-import com.taobao.weex.ui.WXRenderManager;
-import com.taobao.weex.ui.action.ActionReloadPage;
-import com.taobao.weex.ui.action.BasicGraphicAction;
-import com.taobao.weex.ui.action.GraphicActionAddChildToRichtext;
-import com.taobao.weex.ui.action.GraphicActionAddElement;
-import com.taobao.weex.ui.action.GraphicActionAddEvent;
-import com.taobao.weex.ui.action.GraphicActionAppendTreeCreateFinish;
-import com.taobao.weex.ui.action.GraphicActionCreateBody;
-import com.taobao.weex.ui.action.GraphicActionCreateFinish;
-import com.taobao.weex.ui.action.GraphicActionLayout;
-import com.taobao.weex.ui.action.GraphicActionMoveElement;
-import com.taobao.weex.ui.action.GraphicActionRefreshFinish;
-import com.taobao.weex.ui.action.GraphicActionRemoveChildFromRichtext;
-import com.taobao.weex.ui.action.GraphicActionRemoveElement;
-import com.taobao.weex.ui.action.GraphicActionRemoveEvent;
-import com.taobao.weex.ui.action.GraphicActionRenderSuccess;
-import com.taobao.weex.ui.action.GraphicActionUpdateAttr;
-import com.taobao.weex.ui.action.GraphicActionUpdateRichtextAttr;
-import com.taobao.weex.ui.action.GraphicActionUpdateRichtextStyle;
-import com.taobao.weex.ui.action.GraphicActionUpdateStyle;
-import com.taobao.weex.ui.action.GraphicPosition;
-import com.taobao.weex.ui.action.GraphicSize;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.module.WXDomModule;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXFileUtils;
-import com.taobao.weex.utils.WXJsonUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import com.taobao.weex.utils.WXWsonJSONSwitch;
-import com.taobao.weex.utils.batch.BactchExecutor;
-import com.taobao.weex.utils.batch.Interceptor;
-import com.taobao.weex.utils.tools.LogDetail;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
-import java.io.InputStreamReader;
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Stack;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
-
-/**
- * Manager class for communication between JavaScript and Android.
- * <ol>
- * <li>
- * Handle Android to JavaScript call, can be one of the following
- * <ul>
- * <li>{@link #createInstance(String, String, Map, String)}</li>
- * <li>{@link #destroyInstance(String)}</li>
- * <li>{@link #refreshInstance(String, WXRefreshData)}</li>
- * <li>{@link #registerModules(Map)}</li>
- * <li>{@link #registerComponents(List)}</li>
- * <li>{@link #invokeCallJSBatch(Message)}</li>
- * </ul>
- * </li>
- * <li>
- * Handle JavaScript to Android call
- * </li>
- * <li>
- * Handle next tick of message.
- * </li>
- * </ol>
- */
-public class WXBridgeManager implements Callback, BactchExecutor {
-
-  private static Class clazz_debugProxy = null;
-  public static final String METHOD_CREATE_INSTANCE = "createInstance";
-  public static final String METHOD_CREATE_PAGE_WITH_CONTENT = "CreatePageWithContent";
-  public static final String METHOD_UPDATE_COMPONENT_WITH_DATA = "UpdateComponentData";
-  private static final String METHOD_POST_TASK_TO_MSG_LOOP = "PostTaskToMsgLoop";
-  private static final String METHOD_JSFM_NOT_INIT_IN_EAGLE_MODE = "JsfmNotInitInEagleMode";
-  public static final String METHOD_DESTROY_INSTANCE = "destroyInstance";
-  public static final String METHOD_CALL_JS = "callJS";
-  public static final String METHOD_SET_TIMEOUT = "setTimeoutCallback";
-  public static final String METHOD_REGISTER_MODULES = "registerModules";
-  public static final String METHOD_REGISTER_COMPONENTS = "registerComponents";
-  public static final String METHOD_FIRE_EVENT = "fireEvent";
-  public static final String METHD_FIRE_EVENT_SYNC = "fireEventSync";
-  public static final String METHD_COMPONENT_HOOK_SYNC = "componentHook";
-  public static final String METHOD_CALLBACK = "callback";
-  public static final String METHOD_REFRESH_INSTANCE = "refreshInstance";
-  public static final String METHOD_FIRE_EVENT_ON_DATA_RENDER_NODE = "fireEventOnDataRenderNode";
-  public static final String METHOD_NOTIFY_TRIM_MEMORY = "notifyTrimMemory";
-  public static final String METHOD_NOTIFY_SERIALIZE_CODE_CACHE =
-          "notifySerializeCodeCache";
-  public static final String METHOD_CREATE_INSTANCE_CONTEXT = "createInstanceContext";
-
-  public static final String KEY_METHOD = "method";
-  public static final String KEY_ARGS = "args";
-
-  // args
-  public static final String COMPONENT = "component";
-  public static final String REF = "ref";
-  public static final String MODULE = "module";
-  public static final String METHOD = "method";
-  public static final String KEY_PARAMS = "params";
-  public static final String ARGS = "args";
-  public static final String OPTIONS = "options";
-  public static final String INITLOGFILE = "/jsserver_start.log";
-  private static final String NON_CALLBACK = "-1";
-  private static final String UNDEFINED = "undefined";
-  private static final String BUNDLE_TYPE = "bundleType";
-  private static final String RENDER_STRATEGY = "renderStrategy";
-  private static final int INIT_FRAMEWORK_OK = 1;
-  private static final int CRASHREINIT = 50;
-  static volatile WXBridgeManager mBridgeManager;
-  private static long LOW_MEM_VALUE = 120;
-  public volatile static int reInitCount = 1;
-  private volatile static int sInitFrameWorkCount = 0;
-  private static String crashUrl = null;
-  private static long lastCrashTime = 0;
-
-  private static String mRaxApi = null;
-//  private static String mRaxExtApi = null;
-
-  // add for clound setting, default value is true
-  // can use it to control weex sandbox
-  // if true will open weex sandbox for multi context
-  private volatile static boolean isSandBoxContext = true;
-
-  // add for cloud setting, default value is false.
-  // weexcore use single process or not
-  private static boolean isUseSingleProcess = false;
-  // add for cloud setting, default value is false.
-  // jsEngine use multiThread or not
-  private volatile static boolean isJsEngineMultiThreadEnable = false;
-
-  public enum BundType {
-    Vue,
-    Rax,
-    Others
-  };
-
-  private static final boolean BRIDGE_LOG_SWITCH = false;
-
-  /**
-   * Whether JS Framework(main.js) has been initialized.
-   */
-  private volatile static boolean mInit = false;
-
-  private static String globalConfig = "none";
-  private static String GLOBAL_CONFIG_KEY = "global_switch_config";
-
-  private static Map<String, String> mWeexCoreEnvOptions = new HashMap<>();
-
-  /**
-   * package
-   **/
-  Handler mJSHandler;
-  /**
-   * next tick tasks, can set priority
-   */
-  private WXHashMap<String, ArrayList<WXHashMap<String, Object>>> mNextTickTasks = new WXHashMap<>();
-  /**
-   * JSThread
-   */
-  private WXThread mJSThread;
-  private IWXBridge mWXBridge;
-  private Object mWxDebugProxy;
-
-  private boolean mMock = false;
-
-  private List<Map<String, Object>> mRegisterComponentFailList = new ArrayList<>(8);
-  private List<Map<String, Object>> mRegisterModuleFailList = new ArrayList<>(8);
-  private List<String> mRegisterServiceFailList = new ArrayList<>(8);
-  private HashSet<String> mDestroyedInstanceId = new HashSet<>();
-  private StringBuilder mLodBuilder = new StringBuilder(50);
-  private Interceptor mInterceptor;
-  private WXParams mInitParams;
-
-  private WXBridgeManager() {
-    initWXBridge(WXEnvironment.sRemoteDebugMode);
-    mJSThread = new WXThread("WeexJSBridgeThread", this);
-    mJSHandler = mJSThread.getHandler();
-  }
-
-  public static WXBridgeManager getInstance() {
-    if (mBridgeManager == null) {
-      synchronized (WXBridgeManager.class) {
-        if (mBridgeManager == null) {
-          mBridgeManager = new WXBridgeManager();
-        }
-      }
-    }
-    return mBridgeManager;
-  }
-
-  public void setUseSingleProcess(final boolean flag) {
-    if (flag != isUseSingleProcess) {
-      isUseSingleProcess = flag;
-//      //we should reinit framework if js framework has been initialized
-//      if (isJSFrameworkInit()) {
-//        if (isJSThread()) {
-//          WXSDKEngine.reload();
-//        } else {
-//          post(new Runnable() {
-//            @Override
-//            public void run() {
-//              WXSDKEngine.reload();
-//            }
-//          });
-//        }
-//      }
-    }
-  }
-
-  public void onInteractionTimeUpdate(final String instanceId){
-    post(new Runnable() {
-      @Override
-      public void run() {
-        if (mWXBridge instanceof WXBridge ){
-          ((WXBridge)mWXBridge).nativeOnInteractionTimeUpdate(instanceId);
-        }
-      }
-    });
-  }
-
-  public boolean jsEngineMultiThreadEnable() {
-    return isJsEngineMultiThreadEnable;
-  }
-
-  public void checkJsEngineMultiThread() {
-    boolean flag = false;
-    IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
-    if(wxJscProcessManager!=null) {
-      flag = wxJscProcessManager.enableBackupThread();
-    }
-
-    if(flag == WXBridgeManager.isJsEngineMultiThreadEnable) {
-        return;
-    }
-
-    WXBridgeManager.isJsEngineMultiThreadEnable = flag;
-    //we should reinit framework if js framework has been initialized
-    if (isJSFrameworkInit()) {
-      if (isJSThread()) {
-        WXSDKEngine.reload();
-      } else {
-        post(new Runnable() {
-          @Override
-          public void run() {
-            WXSDKEngine.reload();
-          }
-        });
-      }
-    }
-  }
-  public void setSandBoxContext(final boolean flag) {
-    if (flag != isSandBoxContext) {
-      isSandBoxContext = flag;
-      // use diff context reinit jsf
-      if (isJSThread()) {
-
-        setJSFrameworkInit(false);
-        WXModuleManager.resetAllModuleState();
-        String jsf = "";
-        if (!isSandBoxContext) {
-          jsf = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
-        } else {
-          jsf = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
-        }
-        initFramework(jsf);
-        WXServiceManager.reload();
-        WXModuleManager.reload();
-        WXComponentRegistry.reload();
-      } else {
-        post(new Runnable() {
-          @Override
-          public void run() {
-            setJSFrameworkInit(false);
-            WXModuleManager.resetAllModuleState();
-            String jsf = "";
-            if (!isSandBoxContext) {
-              jsf = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
-            } else {
-              jsf = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
-            }
-            initFramework(jsf);
-            WXServiceManager.reload();
-            WXModuleManager.reload();
-            WXComponentRegistry.reload();
-          }
-        });
-      }
-    }
-  }
-
-  // setJSFrameworkInit and isJSFrameworkInit may use on diff thread
-  // use volatile
-  @RestrictTo(Scope.LIBRARY)
-  boolean isJSFrameworkInit() {
-    return mInit;
-  }
-
-  private void setJSFrameworkInit(boolean init) {
-    mInit = init;
-    WXStateRecord.getInstance().recoreJsfmInitHistory("setJsfmInitFlag:"+init);
-    if (init == true) {
-      onJsFrameWorkInitSuccees();
-    }
-  }
-
-  private void initWXBridge(boolean remoteDebug) {
-    if (remoteDebug && WXEnvironment.isApkDebugable()) {
-      WXEnvironment.sDebugServerConnectable = true;
-    }
-
-    if (WXEnvironment.sDebugServerConnectable && (WXEnvironment.isApkDebugable() || WXEnvironment.sForceEnableDevTool)) {
-      if (WXEnvironment.getApplication() != null) {
-        try {
-          if (clazz_debugProxy == null) {
-            clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
-          }
-          if (clazz_debugProxy != null) {
-            Constructor constructor = clazz_debugProxy.getConstructor(Context.class, IWXDebugConfig.class);
-            if (constructor != null) {
-              mWxDebugProxy = constructor.newInstance(WXEnvironment.getApplication(),
-                      new IWXDebugConfig() {
-                        @Override
-                        public WXBridgeManager getWXJSManager() {
-                          return WXBridgeManager.this;
-                        }
-
-                        @Override
-                        public WXDebugJsBridge getWXDebugJsBridge() {
-                          return new WXDebugJsBridge();
-                        }
-                      });
-              if (mWxDebugProxy != null) {
-                Method method_start = clazz_debugProxy.getMethod("start");
-                if (method_start != null) {
-                  method_start.invoke(mWxDebugProxy);
-                }
-              }
-            }
-          }
-        } catch (Throwable e) {
-          //Ignore, It will throw Exception on Release environment
-        }
-        WXServiceManager.execAllCacheJsService();
-      } else {
-        WXLogUtils.e("WXBridgeManager", "WXEnvironment.sApplication is null, skip init Inspector");
-      }
-    }
-    if (remoteDebug && mWxDebugProxy != null) {
-      try {
-        if (clazz_debugProxy == null ) {
-          clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
-        }
-        if (clazz_debugProxy != null) {
-          Method method_getWXBridge = clazz_debugProxy.getMethod("getWXBridge");
-          if (method_getWXBridge != null) {
-            mWXBridge = (IWXBridge) method_getWXBridge.invoke(mWxDebugProxy);
-          }
-        }
-      } catch (Throwable e) {
-        //Ignore, It will throw Exception on Release environment
-      }
-    } else {
-      mWXBridge = new WXBridge();
-    }
-  }
-
-  public String dumpIpcPageInfo(){
-    if (mWXBridge instanceof WXBridge){
-      return ((WXBridge)mWXBridge).nativeDumpIpcPageQueueInfo();
-    }
-    return "";
-  }
-
-  public boolean isRebootExceedLimit(){
-    return reInitCount > CRASHREINIT;
-  }
-
-  public void stopRemoteDebug() {
-    if (mWxDebugProxy != null) {
-      try {
-        if (clazz_debugProxy == null) {
-          clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
-        }
-        if (clazz_debugProxy != null) {
-          Method method_stop = clazz_debugProxy.getMethod("stop", boolean.class);
-          if (method_stop != null) {
-            method_stop.invoke(mWxDebugProxy, true);
-          }
-        }
-      } catch (Throwable e) {
-        //Ignore, It will throw Exception on Release environment
-      }
-    }
-  }
-
-  public Object callModuleMethod(String instanceId, String moduleStr, String methodStr, JSONArray args) {
-    return callModuleMethod(instanceId, moduleStr, methodStr, args, null);
-  }
-
-  public Object callModuleMethod(String instanceId, String moduleStr, String methodStr, JSONArray args, JSONObject options) {
-    WXSDKInstance wxsdkInstance = WXSDKManager.getInstance()
-            .getSDKInstance(instanceId);
-    if (wxsdkInstance == null) {
-      return null;
-    }
-    if (wxsdkInstance.isNeedValidate()
-            && WXSDKManager.getInstance().getValidateProcessor() != null) {
-      WXValidateProcessor.WXModuleValidateResult validateResult = WXSDKManager
-              .getInstance().getValidateProcessor()
-              .onModuleValidate(wxsdkInstance, moduleStr, methodStr, args, options);
-      if (validateResult == null) {
-        return null;
-      }
-      if (validateResult.isSuccess) {
-        return WXModuleManager.callModuleMethod(instanceId, moduleStr, methodStr,
-                args);
-      } else {
-        JSONObject validateInfo = validateResult.validateInfo;
-        if (validateInfo != null) {
-          WXLogUtils.e("[WXBridgeManager] module validate fail. >>> " + validateInfo.toJSONString());
-        }
-        return validateInfo;
-      }
-    }
-    try {
-      return WXModuleManager.callModuleMethod(instanceId, moduleStr, methodStr, args);
-    }catch(NumberFormatException e){
-      ArrayMap<String, String> ext = new ArrayMap<>();
-      ext.put("moduleName", moduleStr);
-      ext.put("methodName", methodStr);
-      ext.put("args", args.toJSONString());
-      WXLogUtils.e("[WXBridgeManager] callNative : numberFormatException when parsing string to numbers in args", ext.toString());
-      return null;
-    }
-  }
-
-  /**
-   * Model switch. For now, debug model and release model are supported
-   */
-  public void restart() {
-    setJSFrameworkInit(false);
-    WXModuleManager.resetAllModuleState();
-    initWXBridge(WXEnvironment.sRemoteDebugMode);
-    mWXBridge.resetWXBridge(WXEnvironment.sRemoteDebugMode);
-  }
-
-  /**
-   * Set current Instance
-   *
-   * @param instanceId {@link WXSDKInstance#mInstanceId}
-   */
-  public synchronized void setStackTopInstance(final String instanceId) {
-    post(new Runnable() {
-
-      @Override
-      public void run() {
-        mNextTickTasks.setStackTopInstance(instanceId);
-      }
-    },instanceId, null, null);
-  }
-
-  @Override
-  public void post(Runnable r) {
-      postWithName(r,null,null);
-  }
-
-  public void postWithName(Runnable r, WXSDKInstance instance, String runnableName) {
-   Runnable secure = WXThread.secure(r,instance, runnableName);
-    if (mInterceptor != null && mInterceptor.take(secure)) {
-      //task is token by the interceptor
-      return;
-    }
-    if (mJSHandler == null) {
-      return;
-    }
-
-    mJSHandler.post(secure);
-  }
-
-  @Override
-  public void setInterceptor(Interceptor interceptor) {
-    mInterceptor = interceptor;
-  }
-
-  public void post(Runnable r, Object token, WXSDKInstance instance, String runnableName) {
-    if (mJSHandler == null) {
-      return;
-    }
-
-    Message m = Message.obtain(mJSHandler, WXThread.secure(r, instance, runnableName));
-    m.obj = token;
-    m.sendToTarget();
-  }
-
-  public void post(Runnable r, Object token) {
-    post(r, token, null, null);
-  }
-
-  public void postDelay(Runnable r,long delayMillis){
-    if (mJSHandler == null) {
-      return;
-    }
-    mJSHandler.postDelayed(WXThread.secure(r),delayMillis);
-  }
-
-  void setTimeout(String callbackId, String time) {
-    Message message = Message.obtain();
-    message.what = WXJSBridgeMsgType.SET_TIMEOUT;
-    TimerInfo timerInfo = new TimerInfo();
-    timerInfo.callbackId = callbackId;
-    timerInfo.time = (long) Float.parseFloat(time);
-    message.obj = timerInfo;
-
-    mJSHandler.sendMessageDelayed(message, timerInfo.time);
-  }
-
-  public void sendMessageDelayed(Message message, long delayMillis) {
-    if (message == null || mJSHandler == null || mJSThread == null
-            || !mJSThread.isWXThreadAlive() || mJSThread.getLooper() == null) {
-      return;
-    }
-    mJSHandler.sendMessageDelayed(message, delayMillis);
-  }
-
-  public void removeMessage(int what, Object obj) {
-    if (mJSHandler == null || mJSThread == null
-            || !mJSThread.isWXThreadAlive() || mJSThread.getLooper() == null) {
-      return;
-    }
-    mJSHandler.removeMessages(what, obj);
-  }
-
-  public Object callNativeModule(String instanceId, String module, String method, JSONArray arguments, Object options) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(module) || TextUtils.isEmpty(method)) {
-      WXLogUtils.d("[WXBridgeManager] call callNativeModule arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeModule",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> instanceId:").append(instanceId)
-              .append(", module:").append(module).append(", method:").append(method).append(", arguments:").append(arguments);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    try {
-      if (WXDomModule.WXDOM.equals(module)) {
-        WXDomModule dom = WXModuleManager.getDomModule(instanceId);
-        return dom.callDomMethod(method, arguments);
-      } else {
-        return callModuleMethod(instanceId, module,
-              method, arguments);
-      }
-    } catch (Exception e) {
-      String err = "[WXBridgeManager] callNative exception: " + WXLogUtils.getStackTrace(e);
-      WXLogUtils.e(err);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNativeModule",
-              err, null);
-    }
-
-    return null;
-  }
-
-  public Object callNativeModule(String instanceId, String module, String method, JSONArray arguments, JSONObject options) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(module) || TextUtils.isEmpty(method)) {
-      WXLogUtils.d("[WXBridgeManager] call callNativeModule arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeModule",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> instanceId:").append(instanceId)
-              .append(", module:").append(module).append(", method:").append(method).append(", arguments:").append(arguments);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    try {
-      if (WXDomModule.WXDOM.equals(module)) {
-        WXDomModule dom = WXModuleManager.getDomModule(instanceId);
-        if(dom != null){
-          return dom.callDomMethod(method, arguments);
-        } else {
-          createDomModule(WXSDKManager.getInstance().getSDKInstance(instanceId));
-        }
-      } else {
-        return callModuleMethod(instanceId, module,
-              method, arguments, options);
-      }
-    } catch (Exception e) {
-      String err = "[WXBridgeManager] callNativeModule exception: " + WXLogUtils.getStackTrace(e);
-      WXLogUtils.e(err);
-    }
-
-    return null;
-  }
-
-  public Object callNativeComponent(String instanceId, String componentRef, String method, JSONArray arguments, Object options) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(componentRef) || TextUtils.isEmpty(method)) {
-      WXLogUtils.d("[WXBridgeManager] call callNativeComponent arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeComponent",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callNativeComponent >>>> instanceId:").append(instanceId)
-              .append(", componentRef:").append(componentRef).append(", method:").append(method).append(", arguments:").append(arguments);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    try {
-      WXDomModule dom = WXModuleManager.getDomModule(instanceId);
-      if (null != dom){
-        dom.invokeMethod(componentRef, method, arguments);
-      }else {
-        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-        if(null == instance || !instance.isDestroy()){
-          WXLogUtils.e("WXBridgeManager","callNativeComponent exception :null == dom ,method:"+method);
-        }
-      }
-
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callNativeComponent exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNativeComponent",
-              WXLogUtils.getStackTrace(e), null);
-    }
-    return null;
-  }
-
-  /**
-   * Dispatch the native task to be executed.
-   *
-   * @param instanceId {@link WXSDKInstance#mInstanceId}
-   * @param tasks      tasks to be executed
-   * @param callback   next tick id
-   */
-  public int callNative(String instanceId, JSONArray tasks, String callback) {
-
-    if (TextUtils.isEmpty(instanceId) || tasks == null) {
-      WXLogUtils.d("[WXBridgeManager] call callNative arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNative",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callNative >>>> instanceId:").append(instanceId)
-              .append(", tasks:").append(tasks).append(", callback:").append(callback);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-
-    long parseNanos = System.nanoTime();
-    JSONArray array = tasks;
-    parseNanos = System.nanoTime() - parseNanos;
-
-    if (null != array && array.size() > 0) {
-      int size = array.size();
-      try {
-        JSONObject task;
-        for (int i = 0; i < size; ++i) {
-          task = (JSONObject) array.get(i);
-          if (task != null && WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
-            Object module = task.get(MODULE);
-            if (module != null) {
-              if (WXDomModule.WXDOM.equals(module)) {
-                WXDomModule dom = WXModuleManager.getDomModule(instanceId);
-                dom.callDomMethod(task, parseNanos);
-              } else {
-                JSONObject optionObj = task.getJSONObject(OPTIONS);
-                WXStateRecord.getInstance().recordAction(instanceId,"callModuleMethod:"+instanceId+","+module+","+task.get(METHOD));
-                callModuleMethod(instanceId, (String) module,
-                        (String) task.get(METHOD), (JSONArray) task.get(ARGS), optionObj);
-              }
-            } else if (task.get(COMPONENT) != null) {
-              WXDomModule dom = WXModuleManager.getDomModule(instanceId);
-              WXStateRecord.getInstance().recordAction(instanceId,"callDomMethod:"+instanceId+","+task.get(METHOD));
-              dom.invokeMethod((String) task.get(REF), (String) task.get(METHOD), (JSONArray) task.get(ARGS));
-            } else {
-              throw new IllegalArgumentException("unknown callNative");
-            }
-          }
-        }
-      } catch (Exception e) {
-        WXLogUtils.e("[WXBridgeManager] callNative exception: ", e);
-        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNative",
-                WXLogUtils.getStackTrace(e) , null);
-      }
-    }
-
-    if (UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-    // get next tick
-    getNextTick(instanceId, callback);
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  // callUpdateFinish
-  public int callUpdateFinish(String instanceId, String callback) {
-
-    if (TextUtils.isEmpty(instanceId)) {
-      WXLogUtils.d("[WXBridgeManager] call callUpdateFinish arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateFinish",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callUpdateFinish >>>> instanceId:").append(instanceId)
-              .append(", callback:").append(callback);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callUpdateFinish exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateFinish",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    if (callback == null || callback.isEmpty() || UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-    // get next tick
-    getNextTick(instanceId, callback);
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  // callRefreshFinish
-  public int callRefreshFinish(String instanceId, String callback) {
-
-    if (TextUtils.isEmpty(instanceId)) {
-      WXLogUtils.d("[WXBridgeManager] call callRefreshFinish arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRefreshFinish",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callRefreshFinish >>>> instanceId:").append(instanceId)
-              .append(", callback:").append(callback);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-        if (instance != null) {
-          GraphicActionRefreshFinish action = new GraphicActionRefreshFinish(instance);
-          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
-        }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callRefreshFinish exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRefreshFinish",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    if (UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-    // get next tick
-    getNextTick(instanceId, callback);
-    return IWXBridge.INSTANCE_RENDERING;
-
-  }
-
-  public int callReportCrashReloadPage(String instanceId, String crashFile) {
-    boolean isCrashFileEmpty = TextUtils.isEmpty(crashFile);
-    try {
-      String url = null;
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        url = instance.getBundleUrl();
-        instance.setHasException(true);
-      }
-      Map<String,String> extInfo = new HashMap<>(2);
-      extInfo.put("weexCoreThreadStackTrace:",WXBridgeManager.getInstance().getWeexCoreThreadStackTrace());
-      extInfo.put("wxStateInfo",WXStateRecord.getInstance().getStateInfo().toString());
-
-      if(!isCrashFileEmpty) {
-        try {
-            if (WXEnvironment.getApplication() != null) {
-                crashFile = mInitParams.getCrashFilePath() + crashFile;
-                Log.d("jsengine", "callReportCrashReloadPage crashFile:" + crashFile);
-            }
-        } catch (Throwable e) {
-          WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-        WXStateRecord.getInstance().onJSCCrash(TextUtils.isEmpty(instanceId)?"null":instanceId);
-        callReportCrash(crashFile, instanceId, url,extInfo);
-      } else {
-        WXStateRecord.getInstance().onJSEngineReload(TextUtils.isEmpty(instanceId)?"null":instanceId);
-         commitJscCrashAlarmMonitor(IWXUserTrackAdapter.JS_BRIDGE, WXErrorCode.WX_ERR_RELOAD_PAGE, "reboot jsc Engine", instanceId, url,extInfo);
-      }
-
-      WXLogUtils.e("reInitCount:"+reInitCount);
-
-      if (reInitCount > CRASHREINIT) {
-        WXExceptionUtils.commitCriticalExceptionRT("jsEngine", WXErrorCode.WX_ERR_RELOAD_PAGE_EXCEED_LIMIT,
-            "callReportCrashReloadPage","reInitCount:"+reInitCount,extInfo);
-        return IWXBridge.INSTANCE_RENDERING_ERROR;
-      }
-      reInitCount++;
-      // reinit frame work
-      setJSFrameworkInit(false);
-      WXModuleManager.resetAllModuleState();
-      initScriptsFramework("");
-
-      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-        return IWXBridge.DESTROY_INSTANCE;
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callReportCrashReloadPage exception: ", e);
-    }
-    try {
-
-      if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
-        boolean reloadThisInstance = shouldReloadCurrentInstance(
-                WXSDKManager.getInstance().getSDKInstance(instanceId).getBundleUrl());
-        new ActionReloadPage(instanceId, reloadThisInstance).executeAction();
-      }
-
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callReloadPage exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callReportCrashReloadPage",
-              WXLogUtils.getStackTrace(e), null);
-    }
-    return IWXBridge.INSTANCE_RENDERING_ERROR;
-  }
-
-  public boolean shouldReloadCurrentInstance(String aUrl) {
-    long time = System.currentTimeMillis();
-    String bizUrl = aUrl;
-    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
-    if (adapter != null) {
-        boolean check_biz_url = Boolean.parseBoolean(adapter
-                .getConfig("android_weex_ext_config",
-                        "check_biz_url",
-                        "true"));
-        WXLogUtils.e("check_biz_url : " + check_biz_url);
-        if(check_biz_url && !TextUtils.isEmpty(aUrl)) {
-            Uri uri = Uri.parse(aUrl);
-            if(uri != null) {
-                bizUrl = uri.buildUpon().clearQuery().build().toString();
-            }
-        }
-    }
-
-    if (crashUrl == null ||
-            (crashUrl != null && !crashUrl.equals(bizUrl)) ||
-            ((time - lastCrashTime) > 15000)) {
-      crashUrl = bizUrl;
-      lastCrashTime = time;
-      return true;
-    }
-    lastCrashTime = time;
-    return false;
-  }
-
-  public void callReportCrash(String crashFile, final String instanceId, final String url,final Map<String,String> extInfo) {
-    // statistic weex core process crash
-    Date date = new Date();
-    DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
-    String time = format.format(date);
-    final String origin_filename = crashFile + "." + time;
-    File oldfile = new File(crashFile);
-    File newfile = new File(origin_filename);
-    if (oldfile.exists()) {
-      oldfile.renameTo(newfile);
-    }
-    Thread t = new Thread(new Runnable() {
-      public void run() {
-        try {
-          File file = new File(origin_filename);
-          if (file.exists()) {
-            if (file.length() > 0) {
-              StringBuilder result = new StringBuilder();
-              try {
-                BufferedReader br = new BufferedReader(new FileReader(origin_filename));
-                String s = null;
-                // boolean foundStart = false;
-                while ((s = br.readLine()) != null) {
-                  if ("".equals(s)) {
-                    continue;
-                  }
-                  // if (("r0:").equals(s)) {
-                  //  break;
-                  // }
-                  result.append(s + "\n");
-                }
-                commitJscCrashAlarmMonitor(IWXUserTrackAdapter.JS_BRIDGE, WXErrorCode.WX_ERR_JSC_CRASH, result.toString(), instanceId, url,extInfo);
-                br.close();
-              } catch (Exception e) {
-                WXLogUtils.e(WXLogUtils.getStackTrace(e));
-              }
-            } else {
-              WXLogUtils.e("[WXBridgeManager] callReportCrash crash file is empty");
-            }
-            if(!WXEnvironment.isApkDebugable())
-              file.delete();
-          }
-        } catch (Throwable throwable) {
-          WXLogUtils.e("[WXBridgeManager] callReportCrash exception: ", throwable);
-        }
-      }
-    });
-    t.start();
-  }
-
-  private void getNextTick(final String instanceId, final String callback) {
-    addJSTask(METHOD_CALLBACK, instanceId, callback, "{}");
-    sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
-  }
-
-  private void getNextTick(final String instanceId) {
-    addJSTask(METHOD_CALLBACK, instanceId, "", "{}");
-    sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
-  }
-
-  public String syncExecJsOnInstanceWithResult(final String instanceId, final String js, final int type) {
-    final CountDownLatch waitLatch = new CountDownLatch(1);
-    EventResult callback = new EventResult(){
-      @Override
-      public void onCallback(Object result) {
-        super.onCallback(result);
-        waitLatch.countDown();
-      }
-    };
-    try{
-      execJSOnInstance(callback, instanceId, js, type);
-      waitLatch.await(100, TimeUnit.MILLISECONDS);
-      if (callback != null && callback.getResult() != null) {
-        return  callback.getResult().toString();
-      }
-      return "";
-    }catch (Throwable e){
-      WXLogUtils.e("syncCallExecJsOnInstance", e);
-      return  "";
-    }
-  }
-
-  public void loadJsBundleInPreInitMode(final String instanceId, final String js){
-    post(new Runnable() {
-      @Override
-      public void run() {
-        invokeExecJSOnInstance(instanceId, js, -1);
-        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-        if (null != instance && instance.isPreInitMode()){
-          instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
-          instance.getApmForInstance().onStageWithTime(WXInstanceApm.KEY_PAGE_STAGES_END_EXCUTE_BUNDLE,WXUtils.getFixUnixTime()+600);
-        }
-      }
-    });
-  }
-
-  /**
-   * ref, type, data, domChanges
-   * */
-  public EventResult syncCallJSEventWithResult(final String method, final String instanceId, final List<Object> params, final Object... args) {
-    final CountDownLatch waitLatch = new CountDownLatch(1);
-    EventResult callback = new EventResult(){
-      @Override
-      public void onCallback(Object result) {
-        super.onCallback(result);
-        waitLatch.countDown();
-      }
-    };
-    try{
-      asyncCallJSEventWithResult(callback, method, instanceId, params, args);
-      waitLatch.await(100, TimeUnit.MILLISECONDS);
-      return  callback;
-    }catch (Exception e){
-      WXLogUtils.e("syncCallJSEventWithResult", e);
-      return  callback;
-    }
-  }
-
-  public void asyncCallJSEventVoidResult(final String method, final String instanceId, final List<Object> params, final Object... args) {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        try{
-          if (args == null || args.length == 0) {
-            return;
-          }
-
-          ArrayList<Object> argsList = new ArrayList<>();
-          for (Object arg : args) {
-            argsList.add(arg);
-          }
-          if (params != null) {
-            ArrayMap map = new ArrayMap(4);
-            map.put(KEY_PARAMS, params);
-            argsList.add(map);
-          }
-
-          WXHashMap<String, Object> task = new WXHashMap<>();
-          task.put(KEY_METHOD, method);
-          task.put(KEY_ARGS, argsList);
-          Object[] tasks = {task};
-          WXJSObject[] jsArgs = {
-                  new WXJSObject(WXJSObject.String, instanceId),
-                  WXWsonJSONSwitch.toWsonOrJsonWXJSObject(tasks)};
-          invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, jsArgs, true);
-          jsArgs[0] = null;
-          jsArgs = null;
-        }catch (Exception e){
-          WXLogUtils.e("asyncCallJSEventVoidResult" , e);
-        }
-      }
-    });
-  }
-
-  /**
-   * aync call js event and return result in eventResult callback
-   * */
-  private void asyncCallJSEventWithResult(final EventResult eventCallback, final String method, final String instanceId, final List<Object> params, final Object... args) {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        Object result = null;
-        try{
-          if (args == null || args.length == 0) {
-            return;
-          }
-
-          ArrayList<Object> argsList = new ArrayList<>();
-          for (Object arg : args) {
-            argsList.add(arg);
-          }
-          if (params != null) {
-            ArrayMap map = new ArrayMap(4);
-            map.put(KEY_PARAMS, params);
-            argsList.add(map);
-          }
-
-          WXHashMap<String, Object> task = new WXHashMap<>();
-          task.put(KEY_METHOD, method);
-          task.put(KEY_ARGS, argsList);
-          Object[] tasks = {task};
-          WXJSObject[] jsArgs = {
-                  new WXJSObject(WXJSObject.String, instanceId),
-                  WXWsonJSONSwitch.toWsonOrJsonWXJSObject(tasks)};
-          ResultCallback<byte[]> resultCallback = null;
-          if (eventCallback != null) {
-            resultCallback = new ResultCallback<byte[]>() {
-              @Override
-              public void onReceiveResult(byte[] result) {
-                JSONArray arrayResult = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(result);
-                if(arrayResult != null && arrayResult.size() > 0){
-                  eventCallback.onCallback(arrayResult.get(0));
-                }
-              }
-            };
-          }
-          invokeExecJSWithCallback(String.valueOf(instanceId), null, METHOD_CALL_JS,
-                  jsArgs, resultCallback, true);
-          jsArgs[0] = null;
-        }catch (Exception e){
-          WXLogUtils.e("asyncCallJSEventWithResult" , e);
-        }
-      }
-    });
-  }
-
-  private void addJSEventTask(final String method, final String instanceId, final List<Object> params, final Object... args) {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        if (args == null || args.length == 0) {
-          return;
-        }
-
-        ArrayList<Object> argsList = new ArrayList<>();
-        for (Object arg : args) {
-          argsList.add(arg);
-        }
-        if (params != null) {
-          ArrayMap map = new ArrayMap(4);
-          map.put(KEY_PARAMS, params);
-          argsList.add(map);
-        }
-
-        WXHashMap<String, Object> task = new WXHashMap<>();
-        task.put(KEY_METHOD, method);
-        task.put(KEY_ARGS, argsList);
-
-
-        if (mNextTickTasks.get(instanceId) == null) {
-          ArrayList<WXHashMap<String, Object>> list = new ArrayList<>();
-          list.add(task);
-          mNextTickTasks.put(instanceId, list);
-        } else {
-          mNextTickTasks.get(instanceId).add(task);
-        }
-      }
-    });
-  }
-
-  private void addJSTask(final String method, final String instanceId, final Object... args) {
-    addJSEventTask(method, instanceId, null, args);
-  }
-
-  private void sendMessage(String instanceId, int what) {
-    Message msg = Message.obtain(mJSHandler);
-    msg.obj = instanceId;
-    msg.what = what;
-    msg.sendToTarget();
-  }
-
-  /**
-   * Initialize JavaScript framework
-   *
-   * @param framework String representation of the framework to be init.
-   */
-  public synchronized void initScriptsFramework(String framework) {
-    Message msg = mJSHandler.obtainMessage();
-    msg.obj = framework;
-    msg.what = WXJSBridgeMsgType.INIT_FRAMEWORK;
-    msg.setTarget(mJSHandler);
-    msg.sendToTarget();
-  }
-
-  @Deprecated
-  public void fireEvent(final String instanceId, final String ref,
-                        final String type, final Map<String, Object> data) {
-    this.fireEvent(instanceId, ref, type, data, null);
-  }
-
-  /**
-   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
-   *
-   * @param instanceId
-   * @param ref
-   * @param type
-   * @param data
-   * @param domChanges
-   */
-  @Deprecated
-  public void fireEvent(final String instanceId, final String ref,
-                        final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
-    fireEventOnNode(instanceId, ref, type, data, domChanges);
-  }
-
-  /**
-   * Notify the JavaScript about the event happened on Android
-   */
-  public void fireEventOnNode(final String instanceId, final String ref,
-                              final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
-    fireEventOnNode(instanceId, ref, type, data, domChanges, null, null);
-  }
-
-  /**
-   * Notify the JavaScript about the event happened on Android
-   */
-  public void fireEventOnNode(final String instanceId, final String ref,
-                              final String type, final Map<String, Object> data,
-                              final Map<String, Object> domChanges, List<Object> params){
-    fireEventOnNode(instanceId, ref, type, data, domChanges, params, null);
-  }
-
-  public void fireEventOnNode(final String instanceId, final String ref,
-                              final String type, final Map<String, Object> data,
-                              final Map<String, Object> domChanges, List<Object> params,  EventResult callback) {
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)
-            || TextUtils.isEmpty(type) || mJSHandler == null) {
-      return;
-    }
-    if (!checkMainThread()) {
-      throw new WXRuntimeException(
-              "fireEvent must be called by main thread");
-    }
-    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-    if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER ||
-            instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
-      fireEventOnDataRenderNode(instanceId, ref, type, data, domChanges);
-    } else {
-      if(callback == null) {
-        addJSEventTask(METHOD_FIRE_EVENT, instanceId, params, ref, type, data, domChanges);
-        sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
-      }else{
-        asyncCallJSEventWithResult(callback, METHD_FIRE_EVENT_SYNC, instanceId, params, ref, type, data, domChanges);
-      }
-    }
-  }
-
-  private void fireEventOnDataRenderNode(final String instanceId, final String ref,
-                                         final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
-    mJSHandler.postDelayed(WXThread.secure(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-          long start = System.currentTimeMillis();
-          if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.d("fireEventOnDataRenderNode >>>> instanceId:" + instanceId
-                + ", data:" + data);
-          }
-          if (mWXBridge instanceof WXBridge) {
-            ((WXBridge) mWXBridge).fireEventOnDataRenderNode(instanceId, ref, type,
-                (data == null || data.isEmpty()) ? "{}" : JSON.toJSONString(data),
-                (domChanges == null || domChanges.isEmpty()) ? "{}" : JSON.toJSONString(domChanges));
-          }
-          WXLogUtils.renderPerformanceLog("fireEventOnDataRenderNode", System.currentTimeMillis() - start);
-        } catch (Throwable e) {
-          String err = "[WXBridgeManager] fireEventOnDataRenderNode " + WXLogUtils.getStackTrace(e);
-          WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "fireEventOnDataRenderNode",
-              err, null);
-          WXLogUtils.e(err);
-        }
-      }
-    }), 0);
-  }
-
-  private boolean checkMainThread() {
-    return Looper.myLooper() == Looper.getMainLooper();
-  }
-
-
-  /**
-   * Invoke JavaScript callback. Use {@link JSCallback} instead.
-   *
-   * @see #callback(String, String, String)
-   */
-  @Deprecated
-  public void callback(String instanceId, String callback, String data) {
-    callback(instanceId, callback, data, false);
-  }
-
-  /**
-   * Invoke JavaScript callback. Use {@link JSCallback} instead.
-   */
-  @Deprecated
-  public void callback(final String instanceId, final String callback,
-                       final Map<String, Object> data) {
-    callback(instanceId, callback, data, false);
-  }
-
-  /**
-   * Use {@link JSCallback} instead.
-   *
-   * @param instanceId Weex Instance Id
-   * @param callback   callback referenece handle
-   * @param data       callback data
-   * @param keepAlive  if keep callback instance alive for later use
-   */
-  @Deprecated
-  public void callback(final String instanceId, final String callback,
-                       final Object data, boolean keepAlive) {
-    callbackJavascript(instanceId, callback, data, keepAlive);
-  }
-
-  /**
-   * Callback to Javascript function.
-   *
-   * @param instanceId Weex Instance Id
-   * @param callback   callback referenece handle
-   * @param data       callback data
-   * @param keepAlive  if keep callback instance alive for later use
-   */
-  void callbackJavascript(final String instanceId, final String callback,
-                          final Object data, boolean keepAlive) {
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(callback)
-            || mJSHandler == null) {
-      return;
-    }
-
-    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-    if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
-      callbackJavascriptOnDataRender(instanceId, callback, data, keepAlive);
-    } else {
-      addJSTask(METHOD_CALLBACK, instanceId, callback, data, keepAlive);
-      sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
-    }
-  }
-
-  void callbackJavascriptOnDataRender(final String instanceId, final String callback, final Object data, final boolean keepAlive){
-    mJSHandler.postDelayed(WXThread.secure(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          long start = System.currentTimeMillis();
-          String data_str = JSON.toJSONString(data);
-          if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.d("callbackJavascriptOnDataRender >>>> instanceId:" + instanceId
-                + ", data:" + data_str);
-          }
-          if (mWXBridge instanceof WXBridge) {
-            ((WXBridge) mWXBridge).invokeCallbackOnDataRender(instanceId, callback,data_str ,keepAlive);
-          }
-          WXLogUtils.renderPerformanceLog("callbackJavascriptOnDataRender", System.currentTimeMillis() - start);
-        } catch (Throwable e) {
-          String err = "[WXBridgeManager] callbackJavascriptOnDataRender " + WXLogUtils.getStackTrace(e);
-          WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callbackJavascriptOnDataRender",
-              err, null);
-          WXLogUtils.e(err);
-        }
-      }
-    }), 0);
-  }
-
-  /**
-   * Refresh instance
-   */
-  public void refreshInstance(final String instanceId, final WXRefreshData jsonData) {
-    if (TextUtils.isEmpty(instanceId) || jsonData == null) {
-      return;
-    }
-    mJSHandler.postDelayed(WXThread.secure(new Runnable() {
-      @Override
-      public void run() {
-        invokeRefreshInstance(instanceId, jsonData);
-      }
-    }), 0);
-  }
-
-  private void invokeRefreshInstance(String instanceId, WXRefreshData refreshData) {
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (!isSkipFrameworkInit(instanceId) && !isJSFrameworkInit()) {
-        if (instance != null) {
-          instance.onRenderError(
-                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg()
-                          + "invokeRefreshInstance FAILED for JSFrameworkInit FAILED, intance will invoke instance.onRenderError"
-          );
-        }
-        String err = "[WXBridgeManager] invokeRefreshInstance: framework.js uninitialized.";
-        WXLogUtils.e(err);
-        return;
-      }
-      long start = System.currentTimeMillis();
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d("refreshInstance >>>> instanceId:" + instanceId
-                + ", data:" + refreshData.data + ", isDirty:" + refreshData.isDirty);
-      }
-
-      if (refreshData.isDirty) {
-        return;
-      }
-      WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
-              instanceId);
-      WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
-              refreshData.data == null ? "{}" : refreshData.data);
-      WXJSObject[] args = {instanceIdObj, dataObj};
-      mWXBridge.refreshInstance(instanceId, null, METHOD_REFRESH_INSTANCE, args);
-    } catch (Throwable e) {
-      String err = "[WXBridgeManager] invokeRefreshInstance " + WXLogUtils.getStackTrace(e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "invokeRefreshInstance",
-              err, null);
-      WXLogUtils.e(err);
-    }
-  }
-
-  public void commitJscCrashAlarmMonitor(final String type, final WXErrorCode errorCode, String errMsg,
-                                         String instanceId, String url,Map<String, String> extInfo) {
-    if (TextUtils.isEmpty(type) || errorCode == null) {
-      return;
-    }
-
-    Log.d("ReportCrash", " commitJscCrashAlarmMonitor errMsg " + errMsg);
-    String method = "callReportCrash";
-    String exception = "weex core process crash and restart exception";
-    Map<String, String> extParams = new HashMap<String, String>();
-    extParams.put("jscCrashStack", errMsg);
-    if (null != extInfo){
-      extParams.putAll(extInfo);
-    }
-    IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
-    if (adapter != null) {
-      WXJSExceptionInfo jsException = new WXJSExceptionInfo(instanceId, url, errorCode, method, exception, extParams);
-      adapter.onJSException(jsException);
-      // if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.e(jsException.toString());
-      // }
-    }
-  }
-
-  private boolean isSkipFrameworkInit(String instanceId) {
-    final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    return isSkipFrameworkInit(instance);
-  }
-
-  private boolean isSkipFrameworkInit(WXSDKInstance instance) {
-    if (instance == null) {
-      return false;
-    }
-    return instance.skipFrameworkInit();
-  }
-
-  /**
-   * Create instance.
-   */
-  public void createInstance(final String instanceId, final String template,
-                             final Map<String, Object> options, final String data) {
-    createInstance(instanceId, new Script(template), options, data);
-  }
-
-  public void setLogLevel(final int level, final boolean isPerf) {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        if(mWXBridge != null) {
-          mWXBridge.setLogType(level, isPerf);
-        }
-      }
-    });
-  }
-
-  public void createInstance(final String instanceId, final Script template,
-                             final Map<String, Object> options, final String data) {
-    final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance == null) {
-      WXLogUtils.e("WXBridgeManager", "createInstance failed, SDKInstance does not exist");
-      return;
-    }
-    if (TextUtils.isEmpty(instanceId) || template == null || template.isEmpty() || mJSHandler == null) {
-      instance.onRenderError(
-              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() +
-                      " instanceId==" + instanceId + " template ==" + template + " mJSHandler== " + mJSHandler.toString()
-      );
-
-      instance.getApmForInstance().onStage("createInstance failed return; "+TextUtils.isEmpty(instanceId)+ ","+template.isEmpty()+","+(mJSHandler ==null));
-      return;
-    }
-
-    if (!isSkipFrameworkInit(instanceId) && !isJSFrameworkInit() && reInitCount == 1 && !WXEnvironment.sDebugServerConnectable) {
-      instance.onRenderError(
-              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() +
-                      " isJSFrameworkInit==" + isJSFrameworkInit() + " reInitCount == 1" );
-      instance.getApmForInstance().onStage("createInstance failed jsfm isn't init return;");
-      post(new Runnable() {
-        @Override
-        public void run() {
-          initFramework("");
-        }
-      }, instanceId, instance,"initFrameworkInCreateInstance");
-      return;
-    }
-
-    WXModuleManager.createDomModule(instance);
-    instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_START);
-    post(new Runnable() {
-      @Override
-      public void run() {
-        instance.getApmForInstance().onStage("wxLoadBundleStartOnJsThread");
-        long start = System.currentTimeMillis();
-        mWXBridge.setPageArgument(instanceId, "renderTimeOrigin", String.valueOf(instance.getWXPerformance().renderTimeOrigin));
-        mWXBridge.setInstanceRenderType(instance.getInstanceId(), instance.getRenderType());
-        invokeCreateInstance(instance, template, options, data);
-        long end = System.currentTimeMillis();
-        instance.getWXPerformance().callCreateInstanceTime = end - start;
-        instance.getWXPerformance().communicateTime =  instance.getWXPerformance().callCreateInstanceTime;
-      }
-    }, instanceId, instance,"createInstance");
-  }
-
-  private void invokeCreateInstance(@NonNull WXSDKInstance instance, Script template,
-                                    Map<String, Object> options, String data) {
-    // add for sandbox, will delete on sandbox ok
-    if (!isSkipFrameworkInit(instance)){
-      initFramework("");
-    }
-
-    if (mMock) {
-      mock(instance.getInstanceId());
-    } else {
-      if (!isSkipFrameworkInit(instance) && !isJSFrameworkInit()) {
-        String err = "[WXBridgeManager] invokeCreateInstance: framework.js uninitialized.";
-        instance.onRenderError(
-                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg()
-        );
-        WXLogUtils.e(err);
-        instance.getApmForInstance().onStage("framework.js uninitialized and return");
-        return;
-      }
-
-      WXModuleManager.registerWhenCreateInstance();
-
-      try {
-        BundType type = BundType.Others;
-        try {
-          long start = System.currentTimeMillis();
-          type = getBundleType(instance.getBundleUrl(), template.getContent());
-
-          if (WXEnvironment.isOpenDebugLog()) {
-            long end = System.currentTimeMillis();
-            WXLogUtils.e("end getBundleType type:" + type.toString() + " time:" + (end - start));
-          }
-        } catch (Throwable e) {
-          WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-
-        try {
-          if (options == null) {
-            options = new HashMap<>();
-          }
-          // on file there is { "framework": "Vue" } or others
-          if (options.get(BUNDLE_TYPE) == null) {
-            // may vue or Rax
-            if (type == BundType.Vue) {
-              options.put(BUNDLE_TYPE, "Vue");
-            } else if (type == BundType.Rax) {
-              options.put(BUNDLE_TYPE, "Rax");
-            } else {
-              options.put(BUNDLE_TYPE, "Others");
-            }
-            Object recordBundleType = options.get(BUNDLE_TYPE);
-            if (recordBundleType instanceof String && "Others".equalsIgnoreCase((String)recordBundleType)){
-              //same as iOS record
-              recordBundleType = "other";
-            }
-            if (null != recordBundleType){
-              instance.getApmForInstance().addProperty(WXInstanceApm.KEY_PAGE_PROPERTIES_BUNDLE_TYPE, recordBundleType);
-            }
-          }
-          if (options.get("env") == null) {
-            options.put("env", mInitParams.toMap());
-          }
-        } catch (Throwable e) {
-          WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-        instance.bundleType = type;
-        if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-          WXLogUtils.d("createInstance >>>> instanceId:" + instance.getInstanceId()
-                  + ", options:"
-                  + WXJsonUtils.fromObjectToJSONString(options)
-                  + ", data:" + data);
-        }
-        WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
-                instance.getInstanceId());
-        WXJSObject instanceObj = new WXJSObject(WXJSObject.String,
-                template.getContent());
-
-        Object extraOption = null;
-        if(options != null && options.containsKey("extraOption")) {
-           extraOption = options.get("extraOption");
-           options.remove("extraOption");
-        }
-
-        WXJSObject extraOptionObj = new WXJSObject(WXJSObject.JSON,
-                extraOption == null ? "{}"
-                        : WXJsonUtils.fromObjectToJSONString(extraOption));
-
-
-        WXJSObject optionsObj = new WXJSObject(WXJSObject.JSON,
-                options == null ? "{}"
-                        : WXJsonUtils.fromObjectToJSONString(options));
-        optionsObj = optionObjConvert(isSandBoxContext, type, optionsObj);
-        WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
-                data == null ? "{}" : data);
-
-        WXJSObject apiObj;
-        if (type == BundType.Rax || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER) {
-          if (mRaxApi == null) {
-            IWXJsFileLoaderAdapter iwxJsFileLoaderAdapter = WXSDKEngine.getIWXJsFileLoaderAdapter();
-            if(iwxJsFileLoaderAdapter != null) {
-              mRaxApi = iwxJsFileLoaderAdapter.loadRaxApi();
-            }
-
-            if(TextUtils.isEmpty(mRaxApi)) {
-              mRaxApi =  WXFileUtils.loadAsset("weex-rax-api.js", WXEnvironment.getApplication());
-            }
-          }
-          apiObj = new WXJSObject(WXJSObject.String,
-                  mRaxApi);
-        } else {
-          apiObj = new WXJSObject(WXJSObject.String,
-                  "");
-        }
-
-        // When render strategy is data_render, put it into options. Others keep null.
-        WXJSObject renderStrategy = null;
-        if (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER) {
-          renderStrategy = new WXJSObject(WXJSObject.String, WXRenderStrategy.DATA_RENDER.getFlag());
-        } else if (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY) {
-          renderStrategy = new WXJSObject(WXJSObject.String, WXRenderStrategy.DATA_RENDER_BINARY.getFlag());
-          // In DATA_RENDER_BINARY strategy script is binary
-          instanceObj.data = template.getBinary();
-        }else if (instance.getRenderStrategy() == WXRenderStrategy.JSON_RENDER) {
-             renderStrategy = new WXJSObject(WXJSObject.String, WXRenderStrategy.JSON_RENDER.getFlag());
-        }
-
-        WXJSObject[] args = {instanceIdObj, instanceObj, optionsObj,
-                dataObj, apiObj, renderStrategy, extraOptionObj};
-
-        instance.setTemplate(template.getContent());
-
-        instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
-
-        // if { "framework": "Vue" } or  { "framework": "Rax" } will use invokeCreateInstanceContext
-        // others will use invokeExecJS
-        if (!isSandBoxContext) {
-          instance.getApmForInstance().onStage("!isSandBoxContext,and excute");
-          WXLogUtils.e("Instance " + instance.getInstanceId() + " Did Not Render in SandBox Mode");
-          invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
-          return;
-        }
-        if (type == BundType.Vue || type == BundType.Rax
-                || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER
-                || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY
-                || instance.getRenderStrategy() == WXRenderStrategy.JSON_RENDER) {
-          instance.getApmForInstance().onStage("wxBeforeInvokeCreateInstanceContext");
-
-          WXLogUtils.d("Instance " + instance.getInstanceId() + " Render in SandBox Mode And Render Type is "
-                  + type + " Render Strategy is " + instance.getRenderStrategy());
-
-          int ret = invokeCreateInstanceContext(instance.getInstanceId(), null, "createInstanceContext", args, false);
-          instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
-          if(ret == 0) {
-            String err = "[WXBridgeManager] invokeCreateInstance : " + instance.getTemplateInfo();
-            WXLogUtils.e("Instance " + instance.getInstanceId() + "Render error : " + err);
-            instance.onRenderError(
-                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() + err);
-          }
-          return;
-        } else {
-          //bad case for js bundle with out bundletype header //vue or rax
-          //WXExceptionUtils.commitCriticalExceptionRT(
-          //      instance.getInstanceId(),
-          //      WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE,
-          //      "invokeCreateInstance",
-          //      WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE.getErrorMsg(),
-          //      null
-          //);
-
-          WXLogUtils.d("Instance " + instance.getInstanceId() + "Did not Render in SandBox Mode And Render Type is "
-                + type + " Render Strategy is " + instance.getRenderStrategy());
-          instance.getApmForInstance().onStage("StartInvokeExecJSBadBundleType");
-          invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
-          instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
-          return;
-        }
-      } catch (Throwable e) {
-        String err = "[WXBridgeManager] invokeCreateInstance " + e.getCause()
-                + instance.getTemplateInfo();
-        instance.getApmForInstance().onStage("createInstance error :"+e.toString());
-        WXLogUtils.e("Instance " + instance.getInstanceId() + "Render error : " + err);
-        instance.onRenderError(
-                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() + err);
-        WXLogUtils.e(err);
-      }
-    }
-  }
-
-  public WXJSObject optionObjConvert(boolean useSandBox, BundType type, WXJSObject opt) {
-    if (!useSandBox) {
-      return opt;
-    }
-    try {
-      String data = opt.data.toString();
-      JSONObject obj = JSON.parseObject(data);
-      JSONObject optEnv;
-      if ((optEnv = obj.getJSONObject("env")) != null) {
-        JSONObject opts = optEnv.getJSONObject("options");
-        if (opts != null) {
-          for (String s : opts.keySet()) {
-            optEnv.put(s, opts.getString(s));
-          }
-        }
-      }
-      return new WXJSObject(WXJSObject.JSON, obj.toString());
-    } catch (Throwable e) {
-      WXLogUtils.e(WXLogUtils.getStackTrace(e));
-    }
-    return opt;
-
-  }
-
-  /**
-   * check bundleType
-   * @param url
-   * @param temp
-   * @return
-   */
-  public BundType getBundleType(String url, String temp) {
-    try {
-      if (url != null) {
-        Uri uri = Uri.parse(url);
-        String type = uri.getQueryParameter(BUNDLE_TYPE);
-        if ("Vue".equals(type) || "vue".equals(type)) {
-          return BundType.Vue;
-        } else if ("Rax".equals(type) || "rax".equals(type)) {
-          return BundType.Rax;
-        }
-      }
-      if (temp != null) {
-        final String FRAMEWORK="framework", VUE="vue", RAX="rax";
-
-        // Find the first line that starts with '//' and convert it to json
-        int bundleTypeStart = temp.indexOf("//");
-        int bundleTypeEnd = temp.indexOf("\n", bundleTypeStart);
-        JSONObject bundleType = JSONObject.parseObject(
-            temp.substring(bundleTypeStart+2, bundleTypeEnd));
-        String type = bundleType.getString(FRAMEWORK);
-        if(VUE.equalsIgnoreCase(type)){
-          return BundType.Vue;
-        }
-        else if(RAX.equalsIgnoreCase(type)){
-          return BundType.Rax;
-        }
-        else{
-          // '//{ "framework": "Vue"}' is not found.
-          String regEx = "(use)(\\s+)(weex:vue)";
-          Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
-          if (pattern.matcher(temp).find()) {
-            return BundType.Vue;
-          }
-          regEx = "(use)(\\s+)(weex:rax)";
-          pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
-          if (pattern.matcher(temp).find()) {
-            return BundType.Rax;
-          }
-        }
-      }
-      return BundType.Others;
-    } catch (Throwable e) {
-      WXLogUtils.e(WXLogUtils.getStackTrace(e));
-      return BundType.Others;
-    }
-  }
-
-  private void mock(String instanceId) {
-
-  }
-
-  public void destroyInstance(final String instanceId) {
-    if (mJSHandler == null
-            || TextUtils.isEmpty(instanceId)) {
-      return;
-    }
-    if (mDestroyedInstanceId != null) {
-      mDestroyedInstanceId.add(instanceId);
-    }
-    // clear message with instanceId
-    mJSHandler.removeCallbacksAndMessages(instanceId);
-    post(new Runnable() {
-      @Override
-      public void run() {
-        removeTaskByInstance(instanceId);
-        invokeDestroyInstance(instanceId);
-      }
-    }, instanceId, null, "destroyInstance");
-  }
-
-  private void removeTaskByInstance(String instanceId) {
-    mNextTickTasks.removeFromMapAndStack(instanceId);
-  }
-
-  private void invokeDestroyInstance(String instanceId) {
-    try {
-      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-        WXLogUtils.d("destroyInstance >>>> instanceId:" + instanceId);
-      }
-      WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
-              instanceId);
-      WXJSObject[] args = {instanceIdObj};
-      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-        invokeDestoryInstance(instanceId, null, METHOD_DESTROY_INSTANCE, args, true);
-        // invokeExecJS(instanceId, null, METHOD_DESTROY_INSTANCE, args);
-      }
-    } catch (Throwable e) {
-      String err = "[WXBridgeManager] invokeDestroyInstance " + e.getCause();
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "invokeDestroyInstance", err, null);
-      WXLogUtils.e(err);
-    }
-  }
-
-  @Override
-  public boolean handleMessage(Message msg) {
-    if (msg == null) {
-      return false;
-    }
-
-    int what = msg.what;
-    switch (what) {
-      case WXJSBridgeMsgType.INIT_FRAMEWORK:
-        invokeInitFramework(msg);
-        break;
-      case WXJSBridgeMsgType.CALL_JS_BATCH:
-        invokeCallJSBatch(msg);
-        break;
-      case WXJSBridgeMsgType.SET_TIMEOUT:
-        TimerInfo timerInfo = (TimerInfo) msg.obj;
-        if (timerInfo == null) {
-          break;
-        }
-        WXJSObject obj = new WXJSObject(WXJSObject.String, timerInfo.callbackId);
-        WXJSObject[] args = {obj};
-        invokeExecJS("", null, METHOD_SET_TIMEOUT, args);
-        break;
-      case WXJSBridgeMsgType.TAKE_HEAP_SNAPSHOT:
-        if (msg.obj != null) {
-          String filename = (String) msg.obj;
-          mWXBridge.takeHeapSnapshot(filename);
-        }
-        break;
-      default:
-        break;
-    }
-    return false;
-  }
-
-  private void invokeExecJS(String instanceId, String namespace, String function, WXJSObject[] args) {
-    invokeExecJS(instanceId, namespace, function, args, true);
-  }
-
-  public void invokeExecJS(final String instanceId, final String namespace, final String function,
-                           final WXJSObject[] args, boolean logTaskDetail) {
-    if (WXEnvironment.isOpenDebugLog() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
-              .append("function:").append(function);
-      if (logTaskDetail) {
-        mLodBuilder.append(" tasks:").append(argsToJSON(args));
-      }
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-    final long start = System.currentTimeMillis();
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
-      Pair<Pair<String,Object>, Boolean> data = null;
-      if(args.length!=2 || !(args[0].data instanceof String)
-          || !(args[1].data instanceof String)
-          || (data = extractCallbackArgs((String) args[1].data))==null){
-        WXLogUtils.w("invokeExecJS on data render that is not a callback call");
-        return;
-      }
-      callbackJavascriptOnDataRender(instanceId, (String) data.first.first, data.first.second, data.second);
-    } else {
-
-      WXThread.secure(new Runnable() {
-        @Override
-        public void run() {
-          mWXBridge.execJS(instanceId, namespace, function, args);
-        }
-      }, instance, "ExecJs").run();
-    }
-    if (null != instance){
-      long diff = System.currentTimeMillis()-start;
-      instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_NUM,1);
-      instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_TIME,diff);
-      instance.callJsTime(diff);
-    }
-  }
-
-  private Pair<Pair<String,Object>,Boolean> extractCallbackArgs(String data) {
-    try {
-      JSONArray obj = JSON.parseArray(data);
-      JSONObject arg_obj = obj.getJSONObject(0);
-      JSONArray args = arg_obj.getJSONArray("args");
-      if (args.size()!=3){
-        return null;
-      }
-      String method = arg_obj.getString("method");
-      if (!"callback".equals(method)){
-        return null;
-      }
-
-      return new Pair<Pair<String,Object>, Boolean>(new Pair<String, Object>(args.getString(0), args.getJSONObject(1)),args.getBooleanValue(2));
-    } catch (Exception e) {
-      return null;
-    }
-  }
-
-  public int invokeCreateInstanceContext(String instanceId, String namespace, String function,
-                                          WXJSObject[] args, boolean logTaskDetail) {
-    WXLogUtils.d("invokeCreateInstanceContext instanceId:" + instanceId + " function:"
-            + function + String.format(" isJSFrameworkInit:%b", isJSFrameworkInit()));
-    mLodBuilder.append("createInstanceContext >>>> instanceId:").append(instanceId)
-            .append("function:").append(function);
-    if (logTaskDetail)
-      mLodBuilder.append(" tasks:").append(WXJsonUtils.fromObjectToJSONString(args));
-    WXLogUtils.d(mLodBuilder.substring(0));
-    mLodBuilder.setLength(0);
-    // }
-    return mWXBridge.createInstanceContext(instanceId, namespace, function, args);
-  }
-
-  public void invokeDestoryInstance(String instanceId, String namespace, String function,
-                                    WXJSObject[] args, boolean logTaskDetail) {
-    // if (WXEnvironment.isApkDebugable()) {
-    mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
-            .append("function:").append(function);
-    if (logTaskDetail)
-      mLodBuilder.append(" tasks:").append(WXJsonUtils.fromObjectToJSONString(args));
-    WXLogUtils.d(mLodBuilder.substring(0));
-    mLodBuilder.setLength(0);
-    // }
-    mWXBridge.removeInstanceRenderType(instanceId);
-    mWXBridge.destoryInstance(instanceId, namespace, function, args);
-  }
-
-  private void execJSOnInstance(final EventResult eventCallback, final String instanceId, final String js, final int type) {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        String ret = invokeExecJSOnInstance(instanceId, js, type);
-        eventCallback.onCallback(ret);
-      }
-    });
-  }
-
-  private String invokeExecJSOnInstance(String instanceId, String js, int type) {
-    // if (WXEnvironment.isApkDebugable()) {
-    mLodBuilder.append("execJSOnInstance >>>> instanceId:").append(instanceId);
-    WXLogUtils.d(mLodBuilder.substring(0));
-    mLodBuilder.setLength(0);
-    // }
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      return mWXBridge.execJSOnInstance(instanceId, js, type);
-    }
-    return null;
-  }
-
-  private void invokeExecJSWithCallback(String instanceId, String namespace, String function,
-                                        WXJSObject[] args , ResultCallback callback, boolean logTaskDetail){
-    if (WXEnvironment.isOpenDebugLog() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
-              .append("function:").append(function);
-      if(logTaskDetail) {
-        mLodBuilder.append(" tasks:").append(argsToJSON(args));
-      }
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.execJSWithCallback(instanceId, namespace, function, args, callback);
-    }
-  }
-
-  public @NonNull static String argsToJSON(WXJSObject[] args) {
-    StringBuilder builder = new StringBuilder();
-    builder.append("[");
-    for(WXJSObject object : args){
-      builder.append(WXWsonJSONSwitch.fromObjectToJSONString(object));
-      builder.append(",");
-    }
-    builder.append("]");
-    return  builder.toString();
-  }
-
-  private void invokeInitFramework(Message msg) {
-    String framework = "";
-    if (msg.obj != null) {
-      framework = (String) msg.obj;
-    }
-
-    if (WXUtils.getAvailMemory(WXEnvironment.getApplication()) > LOW_MEM_VALUE) {
-      initFramework(framework);
-    }
-  }
-
-  public static long sInitFrameWorkTimeOrigin;
-  public static StringBuilder sInitFrameWorkMsg = new StringBuilder();
-
-  private void initFramework(String framework) {
-    LogDetail logDetail = new LogDetail();
-    logDetail.name("initFramework");
-    logDetail.taskStart();
-    if (WXSDKEngine.isSoInitialized() && !isJSFrameworkInit()) {
-      sInitFrameWorkTimeOrigin = System.currentTimeMillis();
-      if (TextUtils.isEmpty(framework)) {
-        // if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d("weex JS framework from assets");
-        // }
-
-        LogDetail logDetail2 = new LogDetail();
-        logDetail2.name("loadJSFramework");
-        logDetail2.taskStart();
-
-        IWXJsFileLoaderAdapter wxJsFileLoaderAdapter = WXSDKEngine.getIWXJsFileLoaderAdapter();
-
-        if (!isSandBoxContext) {
-          if(wxJsFileLoaderAdapter != null) {
-            framework = wxJsFileLoaderAdapter.loadJsFramework();
-          }
-
-          if(TextUtils.isEmpty(framework)) {
-            framework = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
-          }
-        } else {
-          if(wxJsFileLoaderAdapter != null) {
-            framework = wxJsFileLoaderAdapter.loadJsFrameworkForSandBox();
-          }
-
-          if(TextUtils.isEmpty(framework)) {
-            framework = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
-          }
-        }
-        sInitFrameWorkMsg.append("| weex JS framework from assets, isSandBoxContext: ").append(isSandBoxContext);
-        logDetail2.taskEnd();
-      }
-      if (TextUtils.isEmpty(framework)) {
-        setJSFrameworkInit(false);
-        sInitFrameWorkMsg.append("| framework isEmpty ");
-        WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK,
-                "initFramework", "framework is empty!! ", null);
-        return;
-      }
-      try {
-        if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
-          long start = System.currentTimeMillis();
-          WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkStart();
-          WXEnvironment.sJSFMStartListenerTime = System.currentTimeMillis() - start;
-          try {
-            IWXUserTrackAdapter adapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
-            if (null != adapter){
-              Map<String,Serializable> params = new HashMap<>(1);
-              params.put("time",String.valueOf(WXEnvironment.sJSFMStartListenerTime));
-              adapter.commit(WXEnvironment.getApplication(),"sJSFMStartListener",IWXUserTrackAdapter.COUNTER,null,params);
-            }
-          }catch (Exception e){
-            WXLogUtils.e(WXLogUtils.getStackTrace(e));
-          }
-        }
-
-        long start = System.currentTimeMillis();
-        String crashFile = "";
-        try {
-          crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
-        } catch (Exception e) {
-          WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-        boolean pieSupport = true;
-        try {
-          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
-            pieSupport = false;
-          }
-        } catch (Exception e) {
-          WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-        sInitFrameWorkMsg.append(" | pieSupport:").append(pieSupport);
-        WXLogUtils.d("[WXBridgeManager] initFrameworkEnv crashFile:" + crashFile + " pieSupport:" + pieSupport);
-        // extends initFramework
-        LogDetail logDetail3 = new LogDetail();
-        logDetail3.name("native initFrameworkEnv");
-        logDetail3.taskStart();
-        if (mWXBridge.initFrameworkEnv(framework, assembleDefaultOptions(), crashFile, pieSupport) == INIT_FRAMEWORK_OK) {
-          logDetail3.taskEnd();
-          WXEnvironment.sJSLibInitTime = System.currentTimeMillis() - start;
-          WXEnvironment.sSDKInitTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart;
-          setJSFrameworkInit(true);
-          logDetail.taskEnd();
-          if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
-            WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkReady();
-          }
-
-          execRegisterFailTask();
-          WXEnvironment.JsFrameworkInit = true;
-          sInitFrameWorkCount++;
-          WXLogUtils.e("initFrameWorkCount :"+ sInitFrameWorkCount);
-          registerDomModule();
-          trackComponentAndModulesTime();
-        } else {
-          sInitFrameWorkMsg.append(" | ExecuteJavaScript fail, reInitCount").append(reInitCount);
-          if (reInitCount > 1) {
-            WXLogUtils.e("[WXBridgeManager] invokeReInitFramework  ExecuteJavaScript fail");
-          } else {
-            WXLogUtils.e("[WXBridgeManager] invokeInitFramework  ExecuteJavaScript fail");
-          }
-        }
-      } catch (Throwable e) {
-        sInitFrameWorkMsg.append(" | invokeInitFramework exception ").append(e.toString());
-        if (reInitCount > 1) {
-          WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
-        } else {
-          WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
-        }
-      }
-
-    }
-  }
-
-  private void trackComponentAndModulesTime() {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        WXEnvironment.sComponentsAndModulesReadyTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart;
-      }
-    });
-  }
-
-  @SuppressWarnings("unchecked")
-  private void invokeCallJSBatch(Message message) {
-    if (mNextTickTasks.isEmpty() || !isJSFrameworkInit()) {
-      if (!isJSFrameworkInit()) {
-        WXLogUtils.e("[WXBridgeManager] invokeCallJSBatch: framework.js uninitialized!!  message:" + message.toString());
-      }
-      return;
-    }
-
-    try {
-      Object instanceId = message.obj;
-
-      Object task = null;
-      Stack<String> instanceStack = mNextTickTasks.getInstanceStack();
-      int size = instanceStack.size();
-      for (int i = size - 1; i >= 0; i--) {
-        instanceId = instanceStack.get(i);
-        task = mNextTickTasks.remove(instanceId);
-        if (task != null && !((ArrayList) task).isEmpty()) {
-          break;
-        }
-      }
-      if (null != task){
-        task = ((ArrayList) task).toArray();
-
-        WXJSObject[] args = {
-            new WXJSObject(WXJSObject.String, instanceId),
-            WXWsonJSONSwitch.toWsonOrJsonWXJSObject(task)};
-
-        invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, args);
-      }
-    } catch (Throwable e) {
-      WXLogUtils.e("WXBridgeManager", e);
-      String err = "invokeCallJSBatch#" + WXLogUtils.getStackTrace(e);
-      WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK,
-              "invokeCallJSBatch", err, null);
-    }
-
-    // If task is not empty, loop until it is empty
-    if (!mNextTickTasks.isEmpty()) {
-      mJSHandler.sendEmptyMessage(WXJSBridgeMsgType.CALL_JS_BATCH);
-    }
-  }
-
-  private WXParams assembleDefaultOptions() {
-    checkJsEngineMultiThread();
-
-    Map<String, String> config = WXEnvironment.getConfig();
-    WXParams wxParams = new WXParams();
-    wxParams.setPlatform(config.get(WXConfig.os));
-    wxParams.setCacheDir(config.get(WXConfig.cacheDir));
-    wxParams.setOsVersion(config.get(WXConfig.sysVersion));
-    wxParams.setAppVersion(config.get(WXConfig.appVersion));
-    wxParams.setWeexVersion(config.get(WXConfig.weexVersion));
-    wxParams.setDeviceModel(config.get(WXConfig.sysModel));
-    wxParams.setShouldInfoCollect(config.get("infoCollect"));
-    wxParams.setLogLevel(config.get(WXConfig.logLevel));
-    wxParams.setLayoutDirection(config.get(WXConfig.layoutDirection));
-    wxParams.setUseSingleProcess(isUseSingleProcess ? "true" : "false");
-    wxParams.setCrashFilePath(WXEnvironment.getCrashFilePath(WXEnvironment.getApplication().getApplicationContext()));
-    wxParams.setLibJsbPath(WXEnvironment.CORE_JSB_SO_PATH);
-    wxParams.setLibJssPath(WXEnvironment.getLibJssRealPath());
-    wxParams.setLibIcuPath(WXEnvironment.getLibJssIcuPath());
-    wxParams.setLibLdPath(WXEnvironment.getLibLdPath());
-    String libJScRealPath = WXEnvironment.getLibJScRealPath();
-    wxParams.setLibJscPath(TextUtils.isEmpty(libJScRealPath)? "" : new File(libJScRealPath).getParent());
-    String appName = config.get(WXConfig.appName);
-    if (!TextUtils.isEmpty(appName)) {
-      wxParams.setAppName(appName);
-    }
-    wxParams.setDeviceWidth(TextUtils.isEmpty(config.get("deviceWidth")) ? String.valueOf(WXViewUtils.getScreenWidth(WXEnvironment.sApplication)) : config.get("deviceWidth"));
-    wxParams.setDeviceHeight(TextUtils.isEmpty(config.get("deviceHeight")) ? String.valueOf(WXViewUtils.getScreenHeight(WXEnvironment.sApplication)) : config.get("deviceHeight"));
-    Map<String, String> customOptions = WXEnvironment.getCustomOptions();
-    customOptions.put("enableBackupThread", String.valueOf(jsEngineMultiThreadEnable()));
-    IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
-    if(wxJscProcessManager != null) {
-      customOptions.put("enableBackupThreadCache", String.valueOf(wxJscProcessManager.enableBackUpThreadCache()));
-    }
-
-    if (!WXEnvironment.sUseRunTimeApi){
-      customOptions.put("__enable_native_promise__","true");
-    }
-
-    String enableAlarmSignal = "true";
-    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
-    if (null != adapter){
-      try {
-        if (adapter.checkMode("white_screen_fix_open")){
-          WXEnvironment.isWsFixMode = true;
-          enableAlarmSignal = "true";
-        }else {
-          enableAlarmSignal = adapter.getConfigWhenInit("wxapm","enableAlarmSignal",enableAlarmSignal);
-          WXEnvironment.isWsFixMode = "true".equalsIgnoreCase(enableAlarmSignal);
-        }
-      }catch (Exception e){
-        e.printStackTrace();
-      }
-    }
-    if (null != enableAlarmSignal){
-      customOptions.put("enableAlarmSignal",enableAlarmSignal);
-    }
-    WXLogUtils.e("weex","enableAlarmSignal:"+enableAlarmSignal);
-
-    wxParams.setOptions(customOptions);
-    wxParams.setNeedInitV8(WXSDKManager.getInstance().needInitV8());
-    mInitParams = wxParams;
-    return wxParams;
-  }
-
-  public WXParams getInitParams() {
-    return mInitParams;
-  }
-
-  private void execRegisterFailTask() {
-
-    if (mRegisterModuleFailList.size() > 0) {
-      List<Map<String, Object>> moduleReceiver = new ArrayList<>();
-      for (int i = 0, moduleCount = mRegisterModuleFailList.size(); i < moduleCount; ++i) {
-        invokeRegisterModules(mRegisterModuleFailList.get(i), moduleReceiver);
-      }
-      mRegisterModuleFailList.clear();
-      if (moduleReceiver.size() > 0) {
-        mRegisterModuleFailList.addAll(moduleReceiver);
-      }
-    }
-
-    if (mRegisterComponentFailList.size() > 0) {
-      List<Map<String, Object>> receiver = new ArrayList<>();
-      invokeRegisterComponents(mRegisterComponentFailList, receiver);
-      mRegisterComponentFailList.clear();
-      if (receiver.size() > 0) {
-        mRegisterComponentFailList.addAll(receiver);
-      }
-    }
-
-    if (mRegisterServiceFailList.size() > 0) {
-      List<String> receiver = new ArrayList<>();
-      for (String service : mRegisterServiceFailList) {
-        invokeExecJSService(service, receiver);
-      }
-      mRegisterServiceFailList.clear();
-      if (receiver.size() > 0) {
-        mRegisterServiceFailList.addAll(receiver);
-      }
-    }
-  }
-
-  /**
-   * Register Android module
-   *
-   * @param modules the format is like
-   *                {'dom':['updateAttrs','updateStyle'],'event':['openUrl']}
-   */
-
-  public void registerModules(final Map<String, Object> modules) {
-    if (modules != null && modules.size() != 0) {
-      if (isJSThread()) {
-        invokeRegisterModules(modules, mRegisterModuleFailList);
-      } else {
-        post(new Runnable() {
-          @Override
-          public void run() {
-            invokeRegisterModules(modules, mRegisterModuleFailList);
-          }
-        });
-      }
-    }
-  }
-
-  /**
-   * Registered component
-   */
-  public void registerComponents(final List<Map<String, Object>> components) {
-    if (mJSHandler == null || components == null
-            || components.size() == 0) {
-      return;
-    }
-    Runnable runnable = new Runnable() {
-      @Override
-      public void run() {
-        invokeRegisterComponents(components, mRegisterComponentFailList);
-      }
-    };
-
-    if(isJSThread() && isJSFrameworkInit()){
-      runnable.run();
-    }else{
-      post(runnable);
-    }
-  }
-
-  public void execJSService(final String service) {
-    postWithName(new Runnable() {
-      @Override
-      public void run() {
-        invokeExecJSService(service, mRegisterServiceFailList);
-      }
-    },null,"execJSService");
-  }
-
-  private void invokeExecJSService(String service, List<String> receiver) {
-    try {
-      if (!isJSFrameworkInit()) {
-        WXLogUtils.e("[WXBridgeManager] invoke execJSService: framework.js uninitialized.");
-        receiver.add(service);
-        return;
-      }
-      mWXBridge.execJSService(service);
-    } catch (Throwable e) {
-      WXLogUtils.e("[WXBridgeManager] invokeRegisterService:", e);
-
-      Map<String, String> data = new HashMap<String, String>();
-      data.put("inputParams",service + "||" + receiver.toString());
-
-      WXExceptionUtils.commitCriticalExceptionRT("invokeExecJSService",
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE,
-              "invokeExecJSService",
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE.getErrorMsg()
-                      + "[WXBridgeManager] invokeRegisterService:"
-                      + WXLogUtils.getStackTrace(e),
-              data);
-    }
-  }
-
-  public boolean isJSThread() {
-    return mJSThread != null && mJSThread.getId() == Thread.currentThread().getId();
-  }
-
-  private void invokeRegisterModules(Map<String, Object> modules, List<Map<String, Object>> failReceiver) {
-    if (modules == null || !isJSFrameworkInit()) {
-      if (!isJSFrameworkInit()) {
-        WXLogUtils.d("[WXinvokeRegisterModulesBridgeManager] invokeRegisterModules: framework.js uninitialized.");
-      }
-      failReceiver.add(modules);
-      return;
-    }
-
-    WXJSObject[] args = {WXWsonJSONSwitch.toWsonOrJsonWXJSObject(modules)};
-    String errorMsg = null;
-    try{
-      // TODO use a better way
-      if (mWXBridge instanceof WXBridge) {
-        ((WXBridge) mWXBridge).registerModuleOnDataRenderNode(WXJsonUtils.fromObjectToJSONString(modules));
-      }
-    } catch (Throwable e){
-      WXLogUtils.e("Weex [data_render register err]", e);
-    }
-    try {
-        if(0 == mWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args)) {
-            errorMsg = "execJS error";
-        }
-      try {
-        Iterator<String> iter = modules.keySet().iterator();
-        while (iter.hasNext()) {
-          String module = iter.next();
-          if (module != null) {
-            WXModuleManager.resetModuleState(module, true);
-            //WXLogUtils.e("[WXBridgeManager]invokeRegisterModules METHOD_REGISTER_MODULES success module:" + module);
-          }
-        }
-      } catch (Throwable e) {
-        WXLogUtils.e("Weex [invokeRegisterModules]", e);
-      }
-    } catch (Throwable e) {
-      errorMsg = WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() +
-                " \n " + e.getMessage() + modules.entrySet().toString();
-    }
-
-    if(!TextUtils.isEmpty(errorMsg)) {
-        WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", errorMsg);
-        WXExceptionUtils.commitCriticalExceptionRT(null,
-                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES,
-                "invokeRegisterModules", errorMsg,
-                null );
-    }
-  }
-
-  private void invokeRegisterComponents(List<Map<String, Object>> components, List<Map<String, Object>> failReceiver) {
-    if (components == failReceiver) {
-      throw new RuntimeException("Fail receiver should not use source.");
-    }
-    if (!isJSFrameworkInit()) {
-      //WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents: framework.js uninitialized.");
-
-      for (Map<String, Object> comp : components) {
-        failReceiver.add(comp);
-      }
-      return;
-    }
-    if (components == null) {
-      return;
-    }
-
-    try{
-      // TODO use a better way
-      if (mWXBridge instanceof WXBridge) {
-        ((WXBridge) mWXBridge).registerComponentOnDataRenderNode(WXJsonUtils.fromObjectToJSONString(components));
-      }
-    } catch (Throwable e){
-      WXLogUtils.e("Weex [data_render register err]", e);
-    }
-
-    WXJSObject[] args = {WXWsonJSONSwitch.toWsonOrJsonWXJSObject(components)};
-    String errorMsg = null;
-    try {
-      if(0 == mWXBridge.execJS("", null, METHOD_REGISTER_COMPONENTS, args)) {
-          errorMsg = "execJS error";
-      }
-    } catch (Throwable e) {
-        errorMsg = WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT
-                + args.toString()
-                + WXLogUtils.getStackTrace(e);
-    }
-
-    if(!TextUtils.isEmpty(errorMsg)) {
-        WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents ", errorMsg);
-        WXExceptionUtils.commitCriticalExceptionRT(null,
-                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT,
-                METHOD_REGISTER_COMPONENTS, errorMsg,
-                null);
-    }
-  }
-
-  public void destroy() {
-    if (mJSThread != null) {
-      mJSThread.quit();
-    }
-    mBridgeManager = null;
-    if (mDestroyedInstanceId != null) {
-      mDestroyedInstanceId.clear();
-    }
-
-  }
-
-  /**
-   * Report JavaScript Exception
-   */
-  public void reportJSException(String instanceId, String function,
-                                String exception) {
-    WXLogUtils.e("reportJSException >>>> instanceId:" + instanceId
-            + ", exception function:" + function + ", exception:"
-            + exception);
-    WXSDKInstance instance = null;
-    WXErrorCode reportErrorCode = WXErrorCode.WX_ERR_JS_EXECUTE;
-    if (instanceId != null && (instance = WXSDKManager.getInstance().getSDKInstance(instanceId)) != null) {
-      instance.setHasException(true);
-      exception +=   "\n getTemplateInfo==" +instance.getTemplateInfo();//add network header info
-      if ((METHOD_CREATE_INSTANCE.equals(function)) || !instance.isContentMd5Match()) {
-        try {
-          //data render mode should report exception instead of reload page,
-          // so we use !isSkipFrameworkInit(instanceId) to skip the positive branch of if clause.
-          if (!isSkipFrameworkInit(instanceId) && isJSFrameworkInit() && (reInitCount > 1 && reInitCount < 10) && !instance.isNeedReLoad()) {
-            new ActionReloadPage(instanceId, true).executeAction();
-            instance.setNeedLoad(true);
-            return;
-          } else {
-            String errorMsg = new StringBuilder()
-                .append(WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg())
-                .append(", exception function:").append(function)
-                .append(", exception:").append(exception)
-                .append(", extInitTime:").append(System.currentTimeMillis()-WXBridgeManager.sInitFrameWorkTimeOrigin).append("ms")
-                .append(", extInitErrorMsg:").append(WXBridgeManager.sInitFrameWorkMsg.toString())
-                .toString();
-            instance.onRenderError(//DegradPassivity to H5
-                     WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
-                     errorMsg
-            );
-            if (!WXEnvironment.sInAliWeex){
-              WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE, function,exception,null);
-            }
-            return;
-          }
-        } catch (Exception e) {
-          WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-      }
-      if (METHOD_CREATE_INSTANCE.equals(function) && !instance.getApmForInstance().hasAddView){
-        reportErrorCode = WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE;
-      } else if ( METHOD_CREATE_INSTANCE_CONTEXT.equals(function) && !instance.getApmForInstance().hasAddView){
-        reportErrorCode = WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE_CONTEXT;
-      } else if (
-          (METHOD_UPDATE_COMPONENT_WITH_DATA.equals(function) ||
-          METHOD_CREATE_PAGE_WITH_CONTENT.equals(function) ||
-          METHOD_POST_TASK_TO_MSG_LOOP.equals(function) ||
-              METHOD_JSFM_NOT_INIT_IN_EAGLE_MODE.equals(function) )
-          && !instance.getApmForInstance().hasAddView){
-        reportErrorCode = WXErrorCode.WX_DEGRAD_EAGLE_RENDER_ERROR;
-      }
-      instance.onJSException(reportErrorCode.getErrorCode(), function, exception);
-    }
-    doReportJSException(instanceId,function,reportErrorCode,exception);
-  }
-
-  private void doReportJSException(String instanceId, String function,WXErrorCode reportCode, String exception){
-    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-    IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
-    if (adapter != null) {
-      String exceptionId = instanceId;
-
-      if (TextUtils.isEmpty(instanceId)) {
-        exceptionId = "instanceIdisNull";
-      }
-
-      if (instance == null) {
-        if (("initFramework").equals(function)) {
-          String exceptionExt = null;
-          try {
-            if (WXEnvironment.getApplication() != null) {
-              final String fileName = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath() + INITLOGFILE;
-              try {
-                File file = new File(fileName);
-                if (file.exists()) {
-                  if (file.length() > 0) {
-                    StringBuilder result = new StringBuilder();
-                    try {
-                      InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
-                      BufferedReader br = new BufferedReader(read);
-                      String s = null;
-                      while ((s = br.readLine()) != null) {
-                        result.append(s + "\n");
-                      }
-                      exceptionExt = result.toString();
-                      br.close();
-                    } catch (Exception e) {
-                      WXLogUtils.e(WXLogUtils.getStackTrace(e));
-                    }
-                  }
-                  file.delete();
-                }
-              } catch (Throwable throwable) {
-                WXLogUtils.e(WXLogUtils.getStackTrace(throwable));
-              }
-            }
-          } catch (Throwable e) {
-            WXLogUtils.e(WXLogUtils.getStackTrace(e));
-          }
-          exception += "\n" + exceptionExt;
-          WXLogUtils.e("reportJSException:" + exception);
-
-        }
-      }
-
-
-      WXExceptionUtils.commitCriticalExceptionRT(exceptionId, reportCode,
-            function,
-          reportCode.getErrorMsg() + exception,
-            null);
-
-    }
-  }
-
-  private void registerDomModule() throws WXException {
-    /** Tell Javascript Framework what methods you have. This is Required.**/
-    Map<String, Object> domMap = new HashMap<>();
-    domMap.put(WXDomModule.WXDOM, WXDomModule.METHODS);
-    registerModules(domMap);
-  }
-
-  //This method is deprecated because of performance issue.
-  @Deprecated
-  public void notifyTrimMemory() {
-
-  }
-
-  /**
-   * update js server global config, current support turn wson off
-   * by pass wson_off
-   * */
-  public static void  updateGlobalConfig(String config) {
-    if(TextUtils.isEmpty(config)){
-      config = "none";
-    }
-    if(!TextUtils.equals(config, globalConfig)){
-      globalConfig = config;
-      WXEnvironment.addCustomOptions(GLOBAL_CONFIG_KEY, globalConfig);
-      Runnable runnable = new Runnable() {
-        @Override
-        public void run() {
-          if(mBridgeManager != null){
-            if(mBridgeManager.isJSFrameworkInit()){
-              if(mBridgeManager.mWXBridge instanceof WXBridge) {
-                final WXBridge bridge = (WXBridge) mBridgeManager.mWXBridge;
-                bridge.nativeUpdateGlobalConfig(globalConfig);
-              }
-            }
-          }
-          if(globalConfig.contains(WXWsonJSONSwitch.WSON_OFF)){
-            WXWsonJSONSwitch.USE_WSON = false;
-          }else{
-            WXWsonJSONSwitch.USE_WSON = true;
-          }
-        }
-      };
-      if(mBridgeManager != null && mBridgeManager.isJSFrameworkInit()){
-        mBridgeManager.post(runnable);
-      }else{
-        runnable.run();
-      }
-    }
-  }
-
-  public
-  @Nullable
-  Looper getJSLooper() {
-    Looper ret = null;
-    if (mJSThread != null) {
-      ret = mJSThread.getLooper();
-    }
-    return ret;
-  }
-
-  public void notifySerializeCodeCache() {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        if (!isJSFrameworkInit())
-          return;
-
-        invokeExecJS("", null, METHOD_NOTIFY_SERIALIZE_CODE_CACHE, new WXJSObject[0]);
-      }
-    });
-  }
-
-  public void takeJSHeapSnapshot(String filename) {
-    Message msg = mJSHandler.obtainMessage();
-    msg.obj = filename;
-    msg.what = WXJSBridgeMsgType.TAKE_HEAP_SNAPSHOT;
-    msg.setTarget(mJSHandler);
-    msg.sendToTarget();
-  }
-
-  public static class TimerInfo {
-
-    public String callbackId;
-    public long time;
-    public String instanceId;
-  }
-
-  public int callCreateBody(String pageId, String componentType, String ref,
-                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
-                            float[] margins, float[] paddings, float[] borders) {
-
-    if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(componentType) || TextUtils.isEmpty(ref)) {
-      WXLogUtils.d("[WXBridgeManager] call callCreateBody arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(pageId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callCreateBody",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callCreateBody >>>> pageId:").append(pageId)
-              .append(", componentType:").append(componentType).append(", ref:").append(ref)
-              .append(", styles:").append(styles == null ? "{}" : styles.toString())
-              .append(", attributes:").append(attributes)
-              .append(", events:").append(events);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionCreateBody(instance, ref, componentType,
-                styles, attributes, events, margins, paddings, borders);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callCreateBody exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(pageId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callCreateBody",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callAddElement(String pageId, String componentType, String ref, int index, String parentRef,
-                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
-                            float[] margins, float[] paddings, float[] borders,boolean willLayout) {
-    if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(componentType) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callAddElement arguments is null");
-      }
-      WXExceptionUtils.commitCriticalExceptionRT(pageId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddElement",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callAddElement >>>> pageId:").append(pageId)
-              .append(", componentType:").append(componentType).append(", ref:").append(ref).append(", index:").append(index)
-              .append(", parentRef:").append(parentRef)
-              .append(", styles:").append(styles == null ? "{}" : styles.toString())
-              .append(", attributes:").append(attributes)
-              .append(", events:").append(events);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
-      if (instance != null) {
-        final GraphicActionAddElement action = new GraphicActionAddElement(instance, ref, componentType, parentRef, index,
-            styles, attributes, events, margins, paddings, borders);
-        if(willLayout) {
-          instance.addInActiveAddElementAction(ref, action);
-        }else{
-          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(pageId, action);
-        }
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callAddElement exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(pageId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddElement",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callRemoveElement(String instanceId, String ref) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callRemoveElement arguments is null");
-      }
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveElement",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callRemoveElement >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionRemoveElement(instance, ref);
-        if(instance.getInActiveAddElementAction(ref)!=null){
-          instance.removeInActiveAddElmentAction(ref);
-        }
-        else {
-          WXSDKManager.getInstance().getWXRenderManager()
-              .postGraphicAction(action.getPageId(), action);
-        }
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callRemoveElement exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveElement",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callMoveElement(String instanceId, String ref, String parentref, int index) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(parentref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callMoveElement arguments is null");
-      }
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callMoveElement",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callMoveElement >>>> instanceId:").append(instanceId)
-              .append(", parentref:").append(parentref)
-              .append(", index:").append(index)
-              .append(", ref:").append(ref);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionMoveElement(instance, ref, parentref, index);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callMoveElement exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callMoveElement",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callAddEvent(String instanceId, String ref, String event) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(event)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callAddEvent arguments is null");
-      }
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddEvent",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callAddEvent >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref)
-              .append(", event:").append(event);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        new GraphicActionAddEvent(instance, ref, event).executeActionOnRender();
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callAddEvent exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddEvent",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    // get next tick
-    getNextTick(instanceId);
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callRemoveEvent(String instanceId, String ref, String event) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(event)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callRemoveEvent arguments is null");
-      }
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveEvent",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callRemoveEvent >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref)
-              .append(", event:").append(event);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        new GraphicActionRemoveEvent(instance, ref, event).executeActionOnRender();
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callRemoveEvent exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveEvent",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    // get next tick
-    getNextTick(instanceId);
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callUpdateStyle(String instanceId, String ref, HashMap<String, Object> styles,
-                             HashMap<String, String> paddings,
-                             HashMap<String, String> margins,
-                             HashMap<String, String> borders) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callUpdateStyle arguments is null");
-      }
-
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateStyle",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callUpdateStyle >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref).append(", styles:").append(styles == null ? "{}" : styles.toString())
-              .append(", paddings:").append(paddings.toString())
-                      .append(", margins:").append(margins.toString())
-                              .append(", borders:").append(borders.toString());
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionUpdateStyle(instance, ref, styles, paddings, margins, borders);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callUpdateStyle exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateStyle",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callUpdateAttrs(String instanceId, String ref, HashMap<String, String> attrs) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callUpdateAttrs arguments is null");
-      }
-
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateAttrs",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callUpdateAttrs >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref).append(", attrs:").append(attrs.toString());
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionUpdateAttr(instance, ref, attrs);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callUpdateAttrs exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateAttrs",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  private void setExceedGPULimitComponentsInfo(String instanceId,String ref,GraphicSize layoutSize){
-    float limit = WXRenderManager.getOpenGLRenderLimitValue();
-    if(limit > 0 && (layoutSize.getHeight() > limit || layoutSize.getWidth() > limit)){
-      JSONObject ext = new JSONObject();
-      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instanceId,ref);
-      ext.put("GPU limit",String.valueOf(limit));
-      ext.put("component.width",String.valueOf(layoutSize.getWidth()));
-      ext.put("component.height",String.valueOf(layoutSize.getHeight()));
-      if (component.getComponentType() != null && !component.getComponentType().isEmpty()) {
-        ext.put("component.type", component.getComponentType());
-      }
-      if (component.getStyles() != null && !component.getStyles().isEmpty()) {
-        ext.put("component.style", component.getStyles().toString());
-      }
-      if (component.getAttrs() != null && !component.getAttrs().isEmpty()) {
-        ext.put("component.attr", component.getAttrs().toString());
-      }
-      if (component.getEvents() != null && !component.getEvents().isEmpty()) {
-        ext.put("component.event", component.getEvents().toString());
-      }
-      if (component.getMargin() != null) {
-        ext.put("component.margin", component.getMargin().toString());
-      }
-      if (component.getPadding() != null) {
-        ext.put("component.padding", component.getPadding().toString());
-      }
-      if (component.getBorder() != null) {
-        ext.put("component.border", component.getBorder().toString());
-      }
-      WXSDKManager.getInstance().getSDKInstance(instanceId).setComponentsInfoExceedGPULimit(ext);
-    }
-  }
-
-  public int callAddChildToRichtext(String instanceId, String nodeType, String ref, String parentRef, String richTextRef,
-                                    HashMap<String, String> styles, HashMap<String, String> attrs){
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callAddChildToRichtext arguments is null");
-      }
-
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddChildToRichtext",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callAddChildToRichtext >>>> instanceId:").append(instanceId)
-              .append(", nodeType:").append(nodeType).append(", ref:").append(ref).append(", parentRef:")
-              .append(parentRef).append(", richTextRef:").append(richTextRef).append(", styles:")
-              .append(styles.toString()).append(", attrs:").append(attrs.toString());
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionAddChildToRichtext(instance,nodeType,ref,parentRef,richTextRef,styles,attrs
-        );
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callAddChildToRichtext exception: ", WXLogUtils.getStackTrace(e));
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddChildToRichtext",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callRemoveChildFromRichtext(String instanceId, String ref, String parentRef, String richTextRef){
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callRemoveChildFromRichtext arguments is null");
-      }
-
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveChildFromRichtext",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callRemoveChildFromRichtext >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref).append(", parentRef:").append(parentRef).append(", richTextRef:").append(richTextRef);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionRemoveChildFromRichtext(instance, ref, parentRef, richTextRef);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callRemoveChildFromRichtext exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveChildFromRichtext",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callUpdateRichtextStyle(String instanceId, String ref, HashMap<String, String> styles, String parentRef, String richTextRef){
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callUpdateRichtextStyle arguments is null");
-      }
-
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateRichtextStyle",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callUpdateRichtextStyle >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref).append(", styles:").append(styles.toString()).append(", parentRef:")
-              .append(parentRef).append(", richTextRef:").append(richTextRef);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionUpdateRichtextStyle(instance, ref, styles, parentRef, richTextRef);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callUpdateRichtextStyle exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateRichtextStyle",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-  public int callUpdateRichtextChildAttr(String instanceId, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef){
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      if (WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("[WXBridgeManager] call callUpdateRichtextChildAttr arguments is null");
-      }
-
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateRichtextChildAttr",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callUpdateRichtextChildAttr >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref).append(", attrs:").append(attrs.toString()).append(", parentRef:")
-              .append(parentRef).append(", richTextRef:").append(richTextRef);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        final BasicGraphicAction action = new GraphicActionUpdateRichtextAttr(instance, ref, attrs, parentRef, richTextRef);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callUpdateRichtextChildAttr exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateRichtextChildAttr",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callLayout(String pageId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index) {
-
-    if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(ref)) {
-        if (WXEnvironment.isApkDebugable()){
-            WXLogUtils.d("[WXBridgeManager] call callLayout arguments is null");
-        }
-
-      WXExceptionUtils.commitCriticalExceptionRT(pageId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callLayout",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callLayout >>>> instanceId:").append(pageId)
-            .append(", ref:").append(ref).append(", height:").append(height).append(", width:").append(width)
-              .append(", top:").append(top)
-              .append(", bottom:").append(bottom)
-              .append(", left:").append(left)
-              .append(", right:").append(right);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
-      if (instance != null) {
-        GraphicSize size = new GraphicSize(width, height);
-        GraphicPosition position = new GraphicPosition(left, top, right, bottom);
-        setExceedGPULimitComponentsInfo(pageId,ref,size);
-        GraphicActionAddElement addAction = instance.getInActiveAddElementAction(ref);
-        if(addAction!=null) {
-          addAction.setRTL(isRTL);
-          addAction.setSize(size);
-          addAction.setPosition(position);
-          if(!TextUtils.equals(ref, WXComponent.ROOT)) {
-            addAction.setIndex(index);
-          }
-          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(pageId, addAction);
-          instance.removeInActiveAddElmentAction(ref);
-        }
-        else {
-          final BasicGraphicAction action = new GraphicActionLayout(instance, ref, position, size, isRTL);
-          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-        }
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callLayout exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(pageId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callLayout",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callAppendTreeCreateFinish(String instanceId, String ref) {
-
-    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
-      WXLogUtils.d("[WXBridgeManager] call callAppendTreeCreateFinish arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAppendTreeCreateFinish",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callAppendTreeCreateFinish >>>> instanceId:").append(instanceId)
-              .append(", ref:").append(ref);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      GraphicActionAppendTreeCreateFinish action = new GraphicActionAppendTreeCreateFinish(instance, ref);
-      WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callAppendTreeCreateFinish exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAppendTreeCreateFinish",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callCreateFinish(String instanceId) {
-
-    if (TextUtils.isEmpty(instanceId)) {
-      WXLogUtils.d("[WXBridgeManager] call callCreateFinish arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callCreateFinish",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callCreateFinish >>>> instanceId:").append(instanceId);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      long start = System.currentTimeMillis();
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        instance.getApmForInstance().onStage("callCreateFinish");
-        instance.firstScreenCreateInstanceTime(start);
-        GraphicActionCreateFinish action = new GraphicActionCreateFinish(instance);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callCreateFinish exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callCreateFinish",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public int callRenderSuccess(String instanceId) {
-
-    if (TextUtils.isEmpty(instanceId)) {
-      WXLogUtils.d("[WXBridgeManager] call callRenderSuccess arguments is null");
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRenderSuccess",
-              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
-      return IWXBridge.INSTANCE_RENDERING_ERROR;
-    }
-
-    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
-      mLodBuilder.append("[WXBridgeManager] callRenderSuccess >>>> instanceId:").append(instanceId);
-      WXLogUtils.d(mLodBuilder.substring(0));
-      mLodBuilder.setLength(0);
-    }
-
-    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    try {
-      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-      if (instance != null) {
-        instance.getApmForInstance().onStage("callRenderSuccess");
-        GraphicActionRenderSuccess action = new GraphicActionRenderSuccess(instance);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXBridgeManager] callRenderSuccess exception: ", e);
-      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRenderSuccess",
-              WXLogUtils.getStackTrace(e), null);
-    }
-
-    return IWXBridge.INSTANCE_RENDERING;
-  }
-
-  public ContentBoxMeasurement getMeasurementFunc(String instanceId, long renderObjectPtr) {
-    ContentBoxMeasurement contentBoxMeasurement = null;
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance != null) {
-      contentBoxMeasurement = instance.getContentBoxMeasurement(renderObjectPtr);
-    }
-    return contentBoxMeasurement;
-  }
-
-  public void bindMeasurementToRenderObject(long ptr){
-    if (isJSFrameworkInit()) {
-      mWXBridge.bindMeasurementToRenderObject(ptr);
-    }
-  }
-
-
-  /**
-   * Native: Layout
-   * @param instanceId
-   * @return
-   */
-  @UiThread
-  public boolean notifyLayout(String instanceId) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      return mWXBridge.notifyLayout(instanceId);
-    }
-    return false;
-  }
-
-  @UiThread
-  public void forceLayout(String instanceId) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.forceLayout(instanceId);
-    }
-  }
-
-  /**
-   * native: OnInstanceClose
-   * should be called on JSThread
-   * @param instanceId
-   */
-  public void onInstanceClose(String instanceId) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.onInstanceClose(instanceId);
-    }
-  }
-
-  /**
-   * native: SetDefaultHeightAndWidthIntoRootDom
-   * @param instanceId
-   * @param defaultWidth
-   * @param defaultHeight
-   */
-  public void setDefaultRootSize(final String instanceId, final float defaultWidth, final float defaultHeight, final boolean isWidthWrapContent, final boolean isHeightWrapContent) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setDefaultHeightAndWidthIntoRootDom(instanceId, defaultWidth, defaultHeight, isWidthWrapContent, isHeightWrapContent);
-    }
-  }
-
-  public void setRenderContentWrapContentToCore(boolean wrap, final String instanceId) {
-    if (isJSFrameworkInit()) {
-      mWXBridge.setRenderContainerWrapContent(wrap, instanceId);
-    }
-  }
-
-  public void setStyleWidth(String instanceId, String ref, float value) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setStyleWidth(instanceId, ref, value);
-    }
-  }
-
-  public void setStyleHeight(String instanceId, String ref, float value) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setStyleHeight(instanceId, ref, value);
-    }
-  }
-
-  public long[] getFirstScreenRenderTime(String instanceId) {
-    if (isJSFrameworkInit()) {
-      return mWXBridge.getFirstScreenRenderTime(instanceId);
-    }
-    return new long[]{0, 0, 0};
-  }
-
-  public long[] getRenderFinishTime(String instanceId) {
-    if (isJSFrameworkInit()) {
-      return mWXBridge.getRenderFinishTime(instanceId);
-    }
-    return new long[]{0, 0, 0};
-  }
-
-  public void setDeviceDisplay(final String instanceId, final float deviceWidth, final float deviceHeight, final float scale) {
-    post(new Runnable() {
-      @Override
-      public void run() {
-        mWXBridge.setDeviceDisplay(instanceId, deviceWidth, deviceHeight, scale);
-      }
-    });
-  }
-
-  public void updateInitDeviceParams(final String width, final String height, final String density, final String statusHeight){
-    if(!isJSFrameworkInit()){
-      return;
-    }
-    post(new Runnable() {
-      @Override
-      public void run() {
-        mWXBridge.updateInitFrameworkParams(WXConfig.deviceWidth, width, WXConfig.deviceWidth);
-      }
-    });
-    post(new Runnable() {
-      @Override
-      public void run() {
-        mWXBridge.updateInitFrameworkParams(WXConfig.deviceHeight, height, WXConfig.deviceHeight);
-      }
-    });
-
-    post(new Runnable() {
-      @Override
-      public void run() {
-        mWXBridge.updateInitFrameworkParams(WXConfig.scale,  density, WXConfig.scale);
-      }
-    });
-
-    if(statusHeight != null){
-      post(new Runnable() {
-        @Override
-        public void run() {
-          mWXBridge.updateInitFrameworkParams(WXConfig.androidStatusBarHeight,  statusHeight, WXConfig.androidStatusBarHeight);
-        }
-      });
-    }
-  }
-
-  public void setMargin(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setMargin(instanceId, ref, edge, value);
-    }
-  }
-
-  public void setPadding(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setPadding(instanceId, ref, edge, value);
-    }
-  }
-
-  public void setPosition(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setPosition(instanceId, ref, edge, value);
-    }
-  }
-
-  public void markDirty(String instanceId, String ref, boolean dirty) {
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.markDirty(instanceId, ref, dirty);
-    }
-  }
-  public void setViewPortWidth(String instanceId,float viewPortWidth){
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setViewPortWidth(instanceId,viewPortWidth);
-    }
-  }
-  public void setPageArgument(String instanceId,String key,String value){
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setPageArgument(instanceId,key,value);
-    }
-  }
-  public void reloadPageLayout(String instanceId){
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.reloadPageLayout(instanceId);
-    }
-  }
-
-  public void setDeviceDisplayOfPage(String instanceId,float width,float height){
-    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
-      mWXBridge.setDeviceDisplayOfPage(instanceId,width,height);
-    }
-  }
-
-  public int callHasTransitionPros(String instanceId, String ref, HashMap<String, String> styles) {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instanceId, ref);
-    if (null == component || null == component.getTransition() || null == component.getTransition().getProperties()) {
-      return IWXBridge.DESTROY_INSTANCE;
-    }
-
-    for(String property : component.getTransition().getProperties()){
-      if(styles.containsKey(property)){
-        return IWXBridge.INSTANCE_RENDERING;
-      }
-    }
-    return IWXBridge.INSTANCE_RENDERING_ERROR;
-  }
-
-  public void registerCoreEnv(String key, String value) {
-    if (isJSFrameworkInit())
-      mWXBridge.registerCoreEnv(key, value);
-    else
-      mWeexCoreEnvOptions.put(key, value);
-  }
-
-  private void onJsFrameWorkInitSuccees() {
-    for (Map.Entry<String, String> entry : mWeexCoreEnvOptions.entrySet()) {
-      mWXBridge.registerCoreEnv(entry.getKey(), entry.getValue());
-    }
-    mWeexCoreEnvOptions.clear();
-  }
-
-  public  String getWeexCoreThreadStackTrace(){
-    if (null == mJSThread){
-      return "null == mJSThread";
-    }
-    StringBuilder stringBuilder = new StringBuilder();
-
-    try {
-      stringBuilder.append(String.format("Thread Name: '%s'\n", mJSThread.getName()));
-      stringBuilder.append(String.format(Locale.ENGLISH,"\"%s\" prio=%d tid=%d %s\n", mJSThread.getName(), mJSThread.getPriority(), mJSThread.getId(), mJSThread.getState()));
-
-      for (StackTraceElement e: mJSThread.getStackTrace()){
-        stringBuilder.append(String.format("\tat %s\n", e.toString()));
-      }
-    } catch (Exception var8) {
-      Log.e("weex", "getJSThreadStackTrace error:", var8);
-    }
-    return stringBuilder.toString();
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXDebugJsBridge.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXDebugJsBridge.java
deleted file mode 100644
index 7b58416..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXDebugJsBridge.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.alibaba.fastjson.JSON;
-import com.taobao.weex.utils.WXWsonJSONSwitch;
-import com.taobao.weex.wson.WsonUtils;
-
-/**
- * Created by darin on 27/03/2018.
- */
-
-public class WXDebugJsBridge {
-
-    public native void resetWXBridge(Object bridge, String className);
-
-    public native void jsHandleSetJSVersion(String jsVersion);
-
-    public native void jsHandleReportException(String instanceId, String func, String exceptionString);
-
-    public native void jsHandleCallNative(String instanceId, byte[] tasks, String callback);
-
-    public void jsHandleCallNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options) {
-        jsHandleCallNativeModule(instanceId, module, method,
-                WXWsonJSONSwitch.convertJSONToWsonIfUseWson(arguments), WXWsonJSONSwitch.convertJSONToWsonIfUseWson(options), true);
-    }
-
-    public native void jsHandleCallNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options, boolean h5);
-
-    public void jsHandleCallNativeComponent(String instanceId, String componentRef, String method, byte[] arguments, byte[] options){
-        jsHandleCallNativeComponent(instanceId, componentRef, method, WXWsonJSONSwitch.convertJSONToWsonIfUseWson(arguments), WXWsonJSONSwitch.convertJSONToWsonIfUseWson(options), true);
-    }
-
-
-    public native void jsHandleCallNativeComponent(String instanceId, String componentRef, String method, byte[] arguments, byte[] options, boolean from);
-
-    public void jsHandleCallAddElement(String instanceId, String ref, String dom, String index){
-        jsHandleCallAddElement(instanceId, ref, WsonUtils.toWson(JSON.parse(dom)), index, true);
-    }
-
-    public native void jsHandleCallAddElement(String instanceId, String ref, byte[] dom, String index, boolean h5);
-
-    public native void jsHandleSetTimeout(String callbackId, String time);
-
-    public native void jsHandleCallNativeLog(byte[] str_array);
-
-    public void jsHandleCallCreateBody(String pageId, String domStr){
-        jsHandleCallCreateBody(pageId, WsonUtils.toWson(JSON.parse(domStr)), true);
-    }
-
-    public native void jsHandleCallCreateBody(String pageId, byte[] domStr, boolean h5);
-
-    public native void jsHandleCallUpdateFinish(String instanceId, byte[] tasks, String callback);
-
-    public native void jsHandleCallCreateFinish(String pageId);
-
-    public native void jsHandleCallRefreshFinish(String instanceId, byte[] tasks, String callback);
-
-    public void jsHandleCallUpdateAttrs(String pageId, String ref, String data){
-        jsHandleCallUpdateAttrs(pageId, ref, WsonUtils.toWson(JSON.parseObject(data)), true);
-    }
-
-    public native void jsHandleCallUpdateAttrs(String pageId, String ref, byte[] data, boolean h5);
-
-    public void jsHandleCallUpdateStyle(String pageId, String ref, String data){
-        byte[] data1 = WsonUtils.toWson(JSON.parseObject(data));
-        jsHandleCallUpdateStyleNative(pageId, ref, data1, true);
-    }
-
-    public native void jsHandleCallUpdateStyleNative(String pageId, String ref, byte[] data, boolean h5);
-
-    public native void jsHandleCallRemoveElement(String pageId, String ref);
-
-    public native void jsHandleCallMoveElement(String pageId, String ref, String parentRef, String index_str);
-
-    public native void jsHandleCallAddEvent(String pageId, String ref, String event);
-
-    public native void jsHandleCallRemoveEvent(String pageId, String ref, String event);
-
-    public native void jsHandleSetInterval(String instanceId, String callbackId, String time);
-
-    public native void jsHandleClearInterval(String instanceId, String callbackId);
-
-    public native void jsHandleCallGCanvasLinkNative(String contextId, int type, String val);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXHashMap.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXHashMap.java
deleted file mode 100644
index 1296af0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXHashMap.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import android.text.TextUtils;
-
-import java.util.HashMap;
-import java.util.Stack;
-
-/**
- * HashMap for Weex
- */
-public class WXHashMap<K, V> extends HashMap<K, V> {
-
-  private static final long serialVersionUID = 4294272345728974369L;
-
-  private Stack<String> instancesStack = new Stack<String>();
-  private String mTag;
-
-  @Override
-  public V put(K key, V value) {
-    if (key != null && key.toString() != null) {
-      if (instancesStack.contains(key)) {
-        instancesStack.remove(key);
-      }
-      instancesStack.push(key.toString());
-    }
-    return super.put(key, value);
-  }
-
-  @Override
-  public V remove(Object key) {
-    return super.remove(key);
-  }
-
-  public V removeFromMapAndStack(Object key) {
-    instancesStack.remove(key);
-    return super.remove(key);
-  }
-
-  /**
-   * Get instance Id of the top of the stack
-   *
-   * @return
-   */
-  public String getStackTopInstanceId() {
-    return instancesStack.isEmpty() ? "" : instancesStack.pop();
-  }
-
-  /**
-   * Move instanceId to the top of the stack
-   *
-   * @param id
-   */
-  public void setStackTopInstance(String id) {
-    if (!TextUtils.isEmpty(id)) {
-      instancesStack.remove(id);
-      instancesStack.push(id);
-    }
-  }
-
-  public Stack<String> getInstanceStack() {
-    return instancesStack;
-  }
-
-  public String getTag() {
-    return mTag;
-  }
-
-  public void setTag(String tag) {
-    this.mTag = tag;
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXJSObject.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXJSObject.java
deleted file mode 100644
index 56ce501..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXJSObject.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-
-import com.taobao.weex.utils.WXJsonUtils;
-
-public class WXJSObject {
-
-    public static final int NUMBER = 1;
-    public static final int String = 2;
-    public static final int JSON = 3;
-    public static final int WSON = 4;
-
-    public Object data;
-    public int type;
-    public String key;
-
-    public WXJSObject(int type, Object data) {
-        this.type = type;
-        this.data = data;
-    }
-
-    public WXJSObject(int type, Object data, String key) {
-        this.type = type;
-        this.data = data;
-        this.key = key;
-    }
-
-    public WXJSObject(Object object) {
-
-        if(null == object){
-            type= String;
-            data = "";
-            return;
-        }
-
-        data = object;
-        if (object instanceof Integer) {
-            type = NUMBER;
-            data = (double) (Integer) object;
-        } else if (object instanceof Double) {
-            type = NUMBER;
-        } else if (object instanceof Float) {
-            type = NUMBER;
-            data = (double) ((Float) object).intValue();
-        } else if (object instanceof String) {
-            type = String;
-        } else if (object instanceof Object) {
-            type = JSON;
-            data = WXJsonUtils.fromObjectToJSONString(object,true);
-        }
-    }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXModuleManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXModuleManager.java
deleted file mode 100644
index f544123..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXModuleManager.java
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import android.content.Intent;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.view.Menu;
-
-import com.alibaba.fastjson.JSONArray;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.common.Destroyable;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXException;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.ui.config.ConfigModuleFactory;
-import com.taobao.weex.ui.module.WXDomModule;
-import com.taobao.weex.ui.module.WXTimerModule;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.cache.RegisterCache;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * Manager class for weex module. There are two types of modules in weex, one is instance-level module,
- * the other is global-level module. Instance-level module will be created every time an instance
- * is created, while global-level module will be singleton in {@link com.taobao.weex.WXSDKEngine}.
- */
-public class WXModuleManager {
-
-  /**
-   * module class object dictionary
-   */
-  private static volatile ConcurrentMap<String, ModuleFactoryImpl> sModuleFactoryMap = new ConcurrentHashMap<>();
-  private static Map<String, WXModule> sGlobalModuleMap = new HashMap<>();
-  private static Map<String, WXDomModule> sDomModuleMap = new HashMap<>();
-
-
-  /**
-   * module object dictionary
-   * K : instanceId, V : Modules
-   */
-  private static Map<String, Map<String, WXModule>> sInstanceModuleMap = new ConcurrentHashMap<>();
-
-
-  public static boolean registerModule(Map<String, RegisterCache.ModuleCache> moduleCacheMap) {
-    if (moduleCacheMap.isEmpty())
-      return true;
-
-    final Iterator<Entry<String, RegisterCache.ModuleCache>> iterator = moduleCacheMap.entrySet().iterator();
-    WXBridgeManager.getInstance()
-            .postWithName(new Runnable() {
-              @Override
-              public void run() {
-                Map<String, Object> modules = new HashMap<>();
-
-                while (iterator.hasNext()) {
-                  Entry<String, RegisterCache.ModuleCache> next = iterator.next();
-                  RegisterCache.ModuleCache value = next.getValue();
-                  String moduleName = value.name;
-                  if (TextUtils.equals(moduleName, WXDomModule.WXDOM)) {
-                    WXLogUtils.e("Cannot registered module with name 'dom'.");
-                    continue;
-                  }
-
-                  if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) {
-                    WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);
-                  }
-                  ModuleFactory factory = value.factory;
-                  try {
-                    registerNativeModule(moduleName, factory);
-                  } catch (WXException e) {
-                    WXLogUtils.e("registerNativeModule" + e);
-                  }
-
-                  if (value.global) {
-                    try {
-                      WXModule wxModule = factory.buildInstance();
-                      wxModule.setModuleName(moduleName);
-                      sGlobalModuleMap.put(moduleName, wxModule);
-                    } catch (Exception e) {
-                      WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e);
-                    }
-                  }
-
-                  try {
-                    sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
-                  } catch (Throwable e) {
-
-                  }
-                  modules.put(moduleName, factory.getMethods());
-                }
-                WXSDKManager.getInstance().registerModules(modules);
-              }
-            },null,"registerModule From Cache");
-    return true;
-  }
-
-  /**
-   * Register module to JavaScript and Android
-   */
-  public static boolean registerModule(final String moduleName, final ModuleFactory factory, final boolean global) throws WXException {
-    if (moduleName == null || factory == null) {
-      return false;
-    }
-
-    if (TextUtils.equals(moduleName,WXDomModule.WXDOM)) {
-      WXLogUtils.e("Cannot registered module with name 'dom'.");
-      return false;
-    }
-
-    if(RegisterCache.getInstance().cacheModule(moduleName,factory,global)) {
-      return true;
-    }
-
-    //execute task in js thread to make sure register order is same as the order invoke register method.
-    WXBridgeManager.getInstance()
-            .postWithName(new Runnable() {
-              @Override
-              public void run() {
-                if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) {
-                  WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);
-                }
-                try {
-                  registerNativeModule(moduleName, factory);
-                } catch (WXException e) {
-                  WXLogUtils.e("registerNativeModule" + e);
-                }
-
-                if (global) {
-                  try {
-                    WXModule wxModule = factory.buildInstance();
-                    wxModule.setModuleName(moduleName);
-                    sGlobalModuleMap.put(moduleName, wxModule);
-                  } catch (Exception e) {
-                    WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e);
-                  }
-                }
-
-                registerJSModule(moduleName, factory);
-
-                try {
-                  sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
-                } catch (Throwable e) {
-
-                }
-              }
-            },null,"registerModule");
-    return true;
-
-  }
-
-  static boolean registerNativeModule(String moduleName, ModuleFactory factory) throws WXException {
-    if (factory == null) {
-      return false;
-    }
-
-    try {
-      if (!sModuleFactoryMap.containsKey(moduleName) ) {
-        sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
-      }
-    }catch (ArrayStoreException e){
-      e.printStackTrace();
-      //ignore:
-      //may throw this exception:
-      //java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
-
-      WXLogUtils.e("[WXModuleManager] registerNativeModule Error moduleName:"  + moduleName + " Error:" + e.toString());
-    }
-    return true;
-  }
-
-  static boolean registerJSModule(String moduleName, ModuleFactory factory) {
-    Map<String, Object> modules = new HashMap<>();
-    modules.put(moduleName, factory.getMethods());
-    WXSDKManager.getInstance().registerModules(modules);
-    return true;
-  }
-
-  static Object callModuleMethod(final String instanceId, String moduleStr, String methodStr, JSONArray args) {
-    ModuleFactory factory = sModuleFactoryMap.get(moduleStr).mFactory;
-    if(factory == null){
-      WXLogUtils.e("[WXModuleManager] module factory not found.");
-      return null;
-    }
-    final WXModule wxModule = findModule(instanceId, moduleStr,factory);
-    if (wxModule == null) {
-      return null;
-    }
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    wxModule.mWXSDKInstance = instance;
-
-    final Invoker invoker = factory.getMethodInvoker(methodStr);
-    try {
-      if(instance != null) {
-        IWXUserTrackAdapter userTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
-        if(userTrackAdapter != null) {
-          HashMap<String, Serializable> data = new HashMap<String, Serializable>();
-          data.put(IWXUserTrackAdapter.MONITOR_ERROR_CODE, "101");
-          data.put(IWXUserTrackAdapter.MONITOR_ARG, moduleStr + "." + methodStr);
-          data.put(IWXUserTrackAdapter.MONITOR_ERROR_MSG, instance.getBundleUrl());
-          userTrackAdapter.commit(instance.getContext(), null, IWXUserTrackAdapter.INVOKE_MODULE, null, data);
-        }
-        return dispatchCallModuleMethod(instance,wxModule,args,invoker);
-      } else {
-        WXLogUtils.e("callModuleMethod >>> instance is null");
-        return null;
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("callModuleMethod >>> invoke module:" + moduleStr + ", method:" + methodStr + " failed. ", e);
-      return null;
-    } finally {
-      if (wxModule instanceof WXDomModule || wxModule instanceof WXTimerModule) {
-        wxModule.mWXSDKInstance = null;
-      }
-    }
-  }
-
-  private static Object dispatchCallModuleMethod(@NonNull WXSDKInstance instance, @NonNull WXModule wxModule,
-                                                 @NonNull JSONArray args, @NonNull Invoker invoker) throws Exception{
-    if(!instance.isPreRenderMode()) {
-      return instance.getNativeInvokeHelper().invoke(wxModule,invoker,args);
-    }
-    // we are in preRender mode
-    if(invoker.isRunOnUIThread()) {/*ASYNC CALL*/
-//      DOMAction moduleInvocationAction = Actions.getModuleInvocationAction(wxModule,args,invoker);
-//      WXSDKManager.getInstance().getWXDomManager().postAction(instance.getInstanceId(), moduleInvocationAction,false);
-      return null;
-    } else {/*SYNC CALL*/
-      return instance.getNativeInvokeHelper().invoke(wxModule,invoker,args);
-    }
-  }
-
-  public static boolean hasModule(String module) {
-    return sGlobalModuleMap.containsKey(module) || sModuleFactoryMap.containsKey(module);
-  }
-
-  private static WXModule findModule(String instanceId, String moduleStr,ModuleFactory factory) {
-    // find WXModule
-    WXModule wxModule = sGlobalModuleMap.get(moduleStr);
-
-    //not global module
-    if (wxModule == null) {
-      Map<String, WXModule> moduleMap = sInstanceModuleMap.get(instanceId);
-      if (moduleMap == null) {
-        moduleMap = new ConcurrentHashMap<>();
-        sInstanceModuleMap.put(instanceId, moduleMap);
-      }
-      // if cannot find the Module, create a new Module and save it
-      wxModule = moduleMap.get(moduleStr);
-      if (wxModule == null) {
-        try {
-          if(factory instanceof ConfigModuleFactory){
-            WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-            wxModule = ((ConfigModuleFactory) factory).buildInstance(instance);
-          }else{
-            wxModule = factory.buildInstance();
-          }
-          wxModule.setModuleName(moduleStr);
-        } catch (Exception e) {
-          WXLogUtils.e(moduleStr + " module build instace failed.", e);
-          return null;
-        }
-        moduleMap.put(moduleStr, wxModule);
-      }
-    }
-
-    return wxModule;
-  }
-
-  /**Hook Activity life cycle callback begin***/
-
-
-  public static void onActivityCreate(String instanceId){
-
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onActivityCreate();
-        } else {
-          WXLogUtils.w("onActivityCreate can not find the " + key + " module");
-        }
-      }
-    }
-
-  }
-
-  public static void onActivityStart(String instanceId){
-
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onActivityStart();
-        } else {
-          WXLogUtils.w("onActivityStart can not find the " + key + " module");
-        }
-      }
-    }
-  }
-
-  public static void onActivityPause(String instanceId){
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onActivityPause();
-        } else {
-          WXLogUtils.w("onActivityPause can not find the " + key + " module");
-        }
-      }
-    }
-  }
-
-  public static void onActivityResume(String instanceId){
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onActivityResume();
-        } else {
-          WXLogUtils.w("onActivityResume can not find the " + key + " module");
-        }
-      }
-    }
-  }
-
-  public static void onActivityStop(String instanceId){
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onActivityStop();
-        } else {
-          WXLogUtils.w("onActivityStop can not find the " + key + " module");
-        }
-      }
-    }
-  }
-
-  public static void onActivityDestroy(String instanceId){
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onActivityDestroy();
-        } else {
-          WXLogUtils.w("onActivityDestroy can not find the " + key + " module");
-        }
-      }
-    }
-  }
-
-  public static boolean onActivityBack(String instanceId){
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          return module.onActivityBack();
-        } else {
-          WXLogUtils.w("onActivityCreate can not find the " + key + " module");
-        }
-      }
-    }
-    return false;
-  }
-
-  public static void onActivityResult(String instanceId,int requestCode, int resultCode, Intent data){
-
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onActivityResult(requestCode, resultCode, data);
-        } else {
-          WXLogUtils.w("onActivityResult can not find the " + key + " module");
-        }
-      }
-    }
-  }
-
-  public static boolean onCreateOptionsMenu(String instanceId,Menu menu) {
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onCreateOptionsMenu(menu);
-        } else {
-          WXLogUtils.w("onActivityResult can not find the " + key + " module");
-        }
-      }
-    }
-    return false;
-  }
-
-  public static void onRequestPermissionsResult(String instanceId ,int requestCode, String[] permissions, int[] grantResults) {
-    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
-    if(modules!=null) {
-      for (String key : modules.keySet()) {
-        WXModule module = modules.get(key);
-        if (module != null) {
-          module.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        } else {
-          WXLogUtils.w("onActivityResult can not find the " + key + " module");
-        }
-      }
-    }
-  }
-
-  public static void destroyInstanceModules(String instanceId) {
-    sDomModuleMap.remove(instanceId);
-    Map<String, WXModule> moduleMap = sInstanceModuleMap.remove(instanceId);
-    if (moduleMap == null || moduleMap.size() < 1) {
-      return;
-    }
-    Iterator<Entry<String, WXModule>> iterator = moduleMap.entrySet().iterator();
-    Entry<String, WXModule> entry;
-    while (iterator.hasNext()) {
-      entry = iterator.next();
-      WXModule module = entry.getValue();
-      if(module instanceof Destroyable){
-        ((Destroyable)module).destroy();
-      }
-
-    }
-  }
-
-  public static void createDomModule(WXSDKInstance instance){
-    if(instance != null) {
-      sDomModuleMap.put(instance.getInstanceId(), new WXDomModule(instance));
-    }
-  }
-
-  public static void destoryDomModule(String instanceID){
-    sDomModuleMap.remove(instanceID);
-  }
-
-  public static WXDomModule getDomModule(String instanceId){
-    return sDomModuleMap.get(instanceId);
-  }
-
-  public static void reload(){
-    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
-      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
-        try {
-          registerJSModule(entry.getKey(), entry.getValue().mFactory);
-        } catch (Throwable e) {
-
-        }
-      }
-    }
-  }
-
-  /**
-   * registerWhenCreateInstance
-   */
-  public static void registerWhenCreateInstance(){
-    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
-      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
-        try {
-          if (!entry.getValue().hasRigster) {
-            registerJSModule(entry.getKey(), entry.getValue().mFactory);
-          }
-        } catch (Throwable e) {
-
-        }
-      }
-    }
-  }
-
-  /**
-   * resetAllModuleState
-   */
-  public static void resetAllModuleState() {
-    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
-      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
-        entry.getValue().hasRigster = false;
-      }
-    }
-  }
-
-  /**
-   * resetModuleState
-   * @param module
-   * @param state
-   */
-  public static void resetModuleState(String module, boolean state) {
-    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
-      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
-        try {
-          if (entry.getKey() != null && entry.getKey().equals(module)) {
-            entry.getValue().hasRigster = state;
-          }
-        } catch (Throwable e) {
-
-        }
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXParams.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXParams.java
deleted file mode 100644
index a20b20f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXParams.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.base.CalledByNative;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-
-public class WXParams implements Serializable {
-
-  private String platform;
-  private String osVersion;
-  private String appVersion;
-  private String weexVersion;
-  private String deviceModel;
-  private String appName;
-  private String deviceWidth;
-  private String deviceHeight;
-  private String shouldInfoCollect;
-  private String logLevel;
-  private String needInitV8;
-  private String cacheDir;
-  private String useSingleProcess;
-  private String crashFilePath;
-  private String libJssPath;
-  private String layoutDirection;
-
-  private String libJscPath;
-  private String libIcuPath;
-  private String libLdPath;
-  private String libJsbPath;
-
-  private Map<String, String> options;
-
-  @CalledByNative
-  public Object getOptions() {
-    return options;
-  }
-
-  public void setOptions(Map<String, String> options) {
-    this.options = options;
-  }
-
-  public String getShouldInfoCollect() {
-    return shouldInfoCollect;
-  }
-
-  public void setShouldInfoCollect(String shouldInfoCollect) {
-    this.shouldInfoCollect = shouldInfoCollect;
-  }
-
-  @CalledByNative
-  public String getPlatform() {
-    return platform;
-  }
-
-  public void setPlatform(String platform) {
-    this.platform = platform;
-  }
-
-  public void setCacheDir(String cache) {
-    this.cacheDir = cache;
-  }
-
-  @CalledByNative
-  public String getCacheDir() {
-    return this.cacheDir;
-  }
-
-  @CalledByNative
-  public String getOsVersion() {
-    return osVersion;
-  }
-
-  public void setOsVersion(String osVersion) {
-    this.osVersion = osVersion;
-  }
-
-  @CalledByNative
-  public String getAppVersion() {
-    return appVersion;
-  }
-
-  public void setAppVersion(String appVersion) {
-    this.appVersion = appVersion;
-  }
-
-  @CalledByNative
-  public String getWeexVersion() {
-    return weexVersion;
-  }
-
-  public void setWeexVersion(String weexVersion) {
-    this.weexVersion = weexVersion;
-  }
-
-  @CalledByNative
-  public String getDeviceModel() {
-    return deviceModel;
-  }
-
-  public void setDeviceModel(String deviceModel) {
-    this.deviceModel = deviceModel;
-  }
-
-  @CalledByNative
-  public String getLayoutDirection() {return layoutDirection;}
-
-  public void setLayoutDirection(String direction) { this.layoutDirection = direction; }
-
-  @CalledByNative
-  public String getAppName() {
-    return appName;
-  }
-
-  public void setAppName(String appName) {
-    this.appName = appName;
-  }
-
-  @CalledByNative
-  public String getDeviceWidth() {
-    return deviceWidth;
-  }
-
-  @CalledByNative
-  public boolean getReleaseMap() {
-    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
-    if (null == adapter){
-      return false;
-    }
-    String doRelease = adapter.getConfigWhenInit("wxapm","release_map","true");
-    WXLogUtils.e("getReleaseMap:"+doRelease);
-    return "true".equalsIgnoreCase(doRelease);
-  }
-
-
-  /**
-   * Device should not be set manually, instead it suppose to represent the width of device and
-   * initialized automatically.
-   * @param deviceWidth
-   */
-  @Deprecated
-  public void setDeviceWidth(String deviceWidth) {
-    this.deviceWidth = deviceWidth;
-  }
-
-  @CalledByNative
-  public String getDeviceHeight() {
-    return deviceHeight;
-  }
-
-  public void setDeviceHeight(String deviceHeight) {
-    this.deviceHeight = deviceHeight;
-  }
-
-  public String getLogLevel() {
-    if(logLevel == null){
-      return "";
-    }
-    return logLevel;
-  }
-
-  @CalledByNative
-  public String getUseSingleProcess() {
-    WXLogUtils.e("getUseSingleProcess is running " + useSingleProcess);
-    return useSingleProcess;
-  }
-
-  public void setUseSingleProcess(String useSingleProcess) {
-    this.useSingleProcess = useSingleProcess;
-  }
-
-  public void setLogLevel(String logLevel) {
-    this.logLevel = logLevel;
-  }
-
-  public String getNeedInitV8() {
-    if(needInitV8 ==null){
-      return "";
-    }
-    return this.needInitV8;
-  }
-
-  public void setNeedInitV8(boolean need) {
-    if (need) {
-      this.needInitV8 = "1";
-    } else {
-      this.needInitV8 = "0";
-    }
-  }
-
-  public void setCrashFilePath(String crashFilePath) {
-    WXLogUtils.e("WXParams","setCrashFilePath: " + crashFilePath);
-    this.crashFilePath = crashFilePath;
-  }
-
-  @CalledByNative
-  public String getCrashFilePath() {
-    WXLogUtils.e("WXParams", "getCrashFilePath:" + crashFilePath);
-    return this.crashFilePath;
-  }
-
-  @CalledByNative
-  public String getLibJssPath() {
-    WXLogUtils.e("getLibJssPath is running " + libJssPath);
-    return libJssPath;
-  }
-
-  @CalledByNative
-  public String getLibJsbPath() {
-    WXLogUtils.e("getLibJsbPath is running " + libJsbPath);
-    return libJsbPath;
-  }
-
-  public void setLibJsbPath(String libJsbPath) {
-    this.libJsbPath = libJsbPath;
-  }
-
-  @CalledByNative
-  public String getLibJscPath() {
-    WXLogUtils.e("getLibJscPath is running " + libJscPath);
-    return libJscPath;
-  }
-  public void setLibJscPath(String libJscPath) {
-    this.libJscPath = libJscPath;
-  }
-  public void setLibJssPath(String libJssPath) {
-    this.libJssPath = libJssPath;
-  }
-  @CalledByNative
-  public String getLibIcuPath() {
-    WXLogUtils.e("getLibIcuPath is running " + libIcuPath);
-    return libIcuPath;
-  }
-
-  public void setLibIcuPath(String libIcuPath) {
-    this.libIcuPath = libIcuPath;
-  }
-
-  @CalledByNative
-  public String getLibLdPath() {
-    WXLogUtils.e("getLibLdPath is running " + libLdPath);
-    return libLdPath;
-  }
-
-  public void setLibLdPath(String libLdPath) {
-    this.libLdPath = libLdPath;
-  }
-
-  @CalledByNative
-  public String getUseRunTimeApi() {
-    return String.valueOf(WXEnvironment.sUseRunTimeApi);
-  }
-
-  public Map<String, Object> toMap() {
-    HashMap<String, Object> map  = new HashMap<>();
-    map.put("appName", appName);
-    map.put("appVersion", appVersion);
-    map.put("cacheDir", cacheDir);
-    map.put("deviceHeight", deviceHeight);
-    map.put("deviceModel", deviceModel);
-    map.put("deviceWidth", deviceWidth);
-    map.put("layoutDirection", layoutDirection);
-    map.put("libJssPath", libJssPath);
-    map.put("logLevel", logLevel);
-    map.put("needInitV8", needInitV8);
-    map.put("osVersion", osVersion);
-    map.put("platform", platform);
-    map.put("useSingleProcess", useSingleProcess);
-    map.put("shouldInfoCollect", shouldInfoCollect);
-    map.put("weexVersion", weexVersion);
-    map.put("crashFilePath", crashFilePath);
-    map.put("libJscPath", libJscPath);
-    map.put("libIcuPath", libIcuPath);
-    map.put("libLdPath", libLdPath);
-    map.put("options", options);
-    map.put("useRunTimeApi",WXEnvironment.sUseRunTimeApi);
-    map.put("__enable_native_promise__",!WXEnvironment.sUseRunTimeApi);
-    return map;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXServiceManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXServiceManager.java
deleted file mode 100644
index 7b052cc..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXServiceManager.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import android.text.TextUtils;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.common.WXJSService;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-public class WXServiceManager {
-
-    private static volatile ConcurrentHashMap<String, WXJSService> sInstanceJSServiceMap = new ConcurrentHashMap<>();
-
-    public static boolean registerService(String name, String serviceScript, Map<String, Object> options) {
-        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(serviceScript)) return false;
-
-        String param1 = "register: global.registerService, unregister: global.unregisterService";
-        String param2 = "serviceName: \"" + name + "\"";
-        for (String key: options.keySet()) {
-            // TODO - why always string?
-            Object value = options.get(key);
-            if (value instanceof  String) {
-                param2 += ", \'" + key + "\': \'" + value + "\'";
-            } else {
-                param2 += ", \'" + key + "\': " + value;
-            }
-        }
-        String serviceJs = String.format(";(function(service, options){ ;%s; })({ %s }, { %s });", serviceScript, param1, param2);
-
-        WXJSService service = new WXJSService();
-        service.setName(name);
-        service.setScript(serviceScript);
-        service.setOptions(options);
-        sInstanceJSServiceMap.put(name, service);
-
-        WXBridgeManager.getInstance().execJSService(serviceJs);
-        return true;
-    }
-
-    public static boolean unRegisterService(String name) {
-        if (TextUtils.isEmpty(name)) return false;
-
-        if(WXEnvironment.isApkDebugable()) {
-            sInstanceJSServiceMap.remove(name);
-        }
-
-        String js = String.format("global.unregisterService( \"%s\" );", name);
-        WXBridgeManager.getInstance().execJSService(js);
-        return true;
-    }
-
-
-    public static void execAllCacheJsService() {
-        for (String serviceName: sInstanceJSServiceMap.keySet()) {
-            WXJSService service = sInstanceJSServiceMap.get(serviceName);
-            registerService(service.getName(), service.getScript(), service.getOptions());
-        }
-    }
-
-    public static WXJSService getService(String serviceName) {
-        if (sInstanceJSServiceMap != null) {
-            return sInstanceJSServiceMap.get(serviceName);
-        }
-        return null;
-    }
-
-    public static void reload() {
-        if(sInstanceJSServiceMap != null && sInstanceJSServiceMap.size() > 0) {
-            WXBridgeManager.getInstance().post(new Runnable() {
-                @Override
-                public void run() {
-                    for (Map.Entry<String, WXJSService> entry : sInstanceJSServiceMap.entrySet()) {
-                        WXJSService service = entry.getValue();
-                        registerService(service.getName(), service.getScript(), service.getOptions());
-                    }
-                }
-            });
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXTask.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXTask.java
deleted file mode 100644
index c236ba6..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXTask.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.taobao.weex.common.IWXObject;
-
-import java.util.ArrayList;
-
-/**
- * Weex JS Native task
- */
-public class WXTask implements IWXObject {
-
-  /**
-   * Native module
-   */
-  public String module;
-
-  /**
-   * The method of native module
-   */
-  public String method;
-
-  /**
-   * The method parameters
-   */
-  public ArrayList<String> args;
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXValidateProcessor.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXValidateProcessor.java
deleted file mode 100644
index 86be2b1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXValidateProcessor.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by fengjunjie
- */
-public interface WXValidateProcessor {
-
-    WXModuleValidateResult onModuleValidate(WXSDKInstance wxsdkInstance, String moduleStr,
-                                            String methodStr, JSONArray params,
-                                            JSONObject options);
-
-    WXComponentValidateResult onComponentValidate(WXSDKInstance wxsdkInstance,
-                                                  String componentName,
-                                                  WXComponent parentComponent);
-
-    boolean needValidate(String bundleUrl);
-
-    class WXComponentValidateResult {
-
-        public boolean isSuccess;
-
-        public String replacedComponent;
-
-        public JSONObject validateInfo;
-
-    }
-
-    class WXModuleValidateResult {
-
-        public boolean isSuccess;
-
-        public JSONObject validateInfo;
-
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
deleted file mode 100644
index ad00f12..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public class Constants {
-
-  public interface Orientation {
-
-    int HORIZONTAL = 0;
-    int VERTICAL = 1;
-  }
-
-  public interface Weex {
-    String REF = "ref";
-    String INSTANCEID = "instanceid";
-    String TYPE = "type";
-  }
-
-  public interface Name {
-
-    String DEFAULT_WIDTH = "defaultWidth";
-    String DEFAULT_HEIGHT = "defaultHeight";
-    String HREF = "href";
-    String WIDTH = "width";
-    String MIN_WIDTH = "minWidth";
-    String MAX_WIDTH = "maxWidth";
-    String HEIGHT = "height";
-    String MIN_HEIGHT = "minHeight";
-    String MAX_HEIGHT = "maxHeight";
-    String ALIGN_ITEMS = "alignItems";
-    String ALIGN_SELF = "alignSelf";
-    String FLEX = "flex";
-    String FLEX_DIRECTION = "flexDirection";
-    String JUSTIFY_CONTENT = "justifyContent";
-    String FLEX_WRAP = "flexWrap";
-
-    String MARGIN = "margin";
-    String MARGIN_TOP = "marginTop";
-    String MARGIN_LEFT = "marginLeft";
-    String MARGIN_RIGHT = "marginRight";
-    String MARGIN_BOTTOM = "marginBottom";
-    String PADDING = "padding";
-    String PADDING_TOP = "paddingTop";
-    String PADDING_LEFT = "paddingLeft";
-    String PADDING_RIGHT = "paddingRight";
-    String PADDING_BOTTOM = "paddingBottom";
-
-    String LEFT = "left";
-    String TOP = "top";
-    String RIGHT = "right";
-    String BOTTOM = "bottom";
-
-
-    String BACKGROUND_COLOR = "backgroundColor";
-    String BACKGROUND_IMAGE = "backgroundImage";
-    String OPACITY = "opacity";
-    String BORDER_RADIUS = "borderRadius";
-    String BORDER_WIDTH = "borderWidth";
-    String BORDER_COLOR = "borderColor";
-    String BORDER_STYLE = "borderStyle";
-    String BORDER_TOP_WIDTH = "borderTopWidth";
-    String BORDER_RIGHT_WIDTH = "borderRightWidth";
-    String BORDER_BOTTOM_WIDTH = "borderBottomWidth";
-    String BORDER_LEFT_WIDTH = "borderLeftWidth";
-    String BORDER_TOP_COLOR = "borderTopColor";
-    String BORDER_RIGHT_COLOR = "borderRightColor";
-    String BORDER_BOTTOM_COLOR = "borderBottomColor";
-    String BORDER_LEFT_COLOR = "borderLeftColor";
-    String BORDER_TOP_LEFT_RADIUS = "borderTopLeftRadius";
-    String BORDER_TOP_RIGHT_RADIUS = "borderTopRightRadius";
-    String BORDER_BOTTOM_RIGHT_RADIUS = "borderBottomRightRadius";
-    String BORDER_BOTTOM_LEFT_RADIUS = "borderBottomLeftRadius";
-    String BORDER_RIGHT_STYLE = "borderRightStyle";
-    String BORDER_BOTTOM_STYLE = "borderBottomStyle";
-    String BORDER_LEFT_STYLE = "borderLeftStyle";
-    String BORDER_TOP_STYLE = "borderTopStyle";
-    String BOX_SHADOW = "boxShadow";
-    String SHADOW_QUALITY = "shadowQuality";
-
-    String POSITION = "position";
-
-    String KEEP_SCROLL_POSITION = "keepScrollPosition";
-
-    String TEXT_DECORATION = "textDecoration";
-    String TEXT_ALIGN = "textAlign";
-    String FONT_WEIGHT = "fontWeight";
-    String FONT_STYLE = "fontStyle";
-    String FONT_SIZE = "fontSize";
-    String COLOR = "color";
-    String LINES = "lines";
-    String FONT_FAMILY = "fontFamily";
-    String TEXT_OVERFLOW = "textOverflow";
-    String ELLIPSIS = "ellipsis";
-    String LINE_HEIGHT = "lineHeight";
-    String DISABLED = "disabled";
-    String VALUE = "value";
-    String IMAGE_QUALITY = "imageQuality";
-    String FILTER = "filter";
-    String QUALITY = "quality";
-    String SRC = "src";
-    String SOURCE = "source";
-    String PLACE_HOLDER = "placeHolder";
-    String RESIZE_MODE = "resizeMode";
-    String AUTO_RECYCLE = "autoBitmapRecycle";
-    String SHOW_INDICATORS = "showIndicators";
-    String AUTO_PLAY = "autoPlay";
-    String AUTOPLAY = "autoplay";
-    String CONTROLS = "controls";
-    String ZORDERTOP = "zOrderTop";
-    String SCROLL_DIRECTION = "scrollDirection";
-    String SCOPE = "scope";
-    String RECYCLE = "recycle";
-    String LOADMORERETRY = "loadmoreretry";
-    String LOADMOREOFFSET = "loadmoreoffset";
-    String RECYCLE_IMAGE = "recycleImage";
-    String LAYOUT = "layout";
-    String SPAN_OFFSETS = "spanOffsets";
-    String COLUMN_WIDTH = "columnWidth";
-    String COLUMN_COUNT = "columnCount";
-    String COLUMN_GAP = "columnGap";
-    String SHOW_SCROLLBAR = "showScrollbar";
-    String LEFT_GAP= "leftGap";
-    String RIGHT_GAP= "rightGap";
-    String OVERFLOW = "overflow";
-    String TYPE = "type";
-    String PLACEHOLDER = "placeholder";
-    String PLACEHOLDER_COLOR = "placeholderColor";
-    String AUTOFOCUS = "autofocus";
-    String SINGLELINE = "singleline";
-    String MAX_LENGTH = "maxLength";
-    String MAXLENGTH = "maxlength";
-    String ROWS = "rows";
-    String CHECKED = "checked";
-    String ANIMATING = "animating";
-    String VISIBILITY = "visibility";
-    String ITEM_COLOR = "itemColor";
-    String ITEM_SELECTED_COLOR = "itemSelectedColor";
-    String ITEM_SIZE = "itemSize";
-    String DISPLAY = "display";
-    String SHOW_LOADING = "show-loading";
-    String SUFFIX = "suffix";
-    String RESIZE = "resize";
-    String IMAGE_SHARPEN = "imageSharpen";
-    String SHARPEN = "sharpen";
-    String PREFIX = "prefix";
-    String INDEX = "index";
-    String INTERVAL = "interval";
-    String PLAY_STATUS = "playStatus";
-    String FONT_FACE = "fontFace";
-    String MAX = "max";
-    String MIN = "min";
-    String NAV_BAR_VISIBILITY = "hidden";
-    String OFFSET_X_ACCURACY = "offsetXAccuracy";
-    String OFFSET_X_RATIO = "offsetXRatio";
-    String ELEVATION = "elevation";
-    String PERSPECTIVE = "perspective";
-    String SCROLLABLE = "scrollable";
-    String DRAGGABLE = "draggable";
-    String DISTANCE_Y = "dy";
-    String PULLING_DISTANCE = "pullingDistance";
-    String VIEW_HEIGHT = "viewHeight";
-    String PREVENT_MOVE_EVENT = "preventMoveEvent";
-    String SELECTION_START = "selectionStart";
-    String SELECTION_END = "selectionEnd";
-    String OFFSET_ACCURACY = "offsetAccuracy";
-    String CONTENT_SIZE = "contentSize";
-    String CONTENT_OFFSET = "contentOffset";
-    String ISDRAGGING = "isDragging";
-    String X = "x";
-    String Y = "y";
-    String RETURN_KEY_TYPE = "returnKeyType";
-    String OFFSET = "offset";
-    String ANIMATED = "animated";
-    String STABLE = "stable";
-    String TRANSFORM = "transform";
-    String TRANSFORM_ORIGIN = "transformOrigin";
-    String KEEP_INDEX = "keepIndex";
-    String KEEP_SELECTION_INDEX = "keepSelectionIndex";
-
-    String INSERT_CELL_ANIMATION = "insertAnimation";
-    String DELETE_CELL_ANIMATION = "deleteAnimation";
-    String AUTO = "auto";
-    String NORMAL = "normal";
-    String ARIA_LABEL = "ariaLabel";
-    String ARIA_HIDDEN = "ariaHidden";
-    String ROLE = "role";
-
-    String LAYERLIMIT = "layerLimit";
-    String LAYER_LIMIT = "layer-limit";
-
-    String DIRECTION = "direction";
-    String RTL = "rtl";
-
-    String STICKY_OFFSET = "stickyOffset";
-    String HAS_FIXED_SIZE = "hasFixedSize";
-    String KEEP_POSITION_LAYOUT_DELAY = "keepPositionLayoutDelay";
-
-    String OVERFLOW_HIDDEN_HEIGHT = "overflowHiddenHeight";
-    String OVERFLOW_HIDDEN_WIDTH = "overflowHiddenWidth";
-
-    String PRIORITY  = "priority";
-
-    String STRATEGY  = "strategy";
-
-    String ALLOW_COPY_PASTE = "allowCopyPaste";
-    String INCLUDE_FONT_PADDING = "includeFontPadding";
-    String ENABLE_COPY = "enableCopy";
-
-    String PAGE_ENABLED = "pagingEnabled";
-    String PAGE_SIZE = "pageSize";
-
-
-
-    interface  Recycler{
-      String LIST_DATA = "listData";
-      String LIST_DATA_ITEM  ="alias";
-      String LIST_DATA_ITEM_INDEX = "index";
-      String LIST_DATA_TEMPLATE_SWITCH_KEY = "switch";
-      String SLOT_TEMPLATE_CASE = "case";
-      String SLOT_TEMPLATE_DEFAULT = "default";
-      String CELL_INDEX = "cellIndex";
-      String TYPE_INDEX = "typeIndex";
-    }
-
-
-    String VIF_FALSE = "ifFalse";
-    String UNDEFINED = "undefined";
-    String FLAT = "flat";
-    String RIPPLE_ENABLED = "rippleEnabled";
-
-    String SHOULD_STOP_PROPAGATION_INIT_RESULT = "shouldStopPropagationInitResult";
-    String SHOULD_STOP_PROPAGATION_INTERVAL = "shouldStopPropagationInterval";
-
-
-    String NEST_SCROLLING_ENABLED = "nestedScrollingEnabled";
-
-    String ORIENTATION  = "orientation";
-  }
-
-  public interface Value {
-
-    int DENSITY = 3;
-    int NAV_BAR_SHOWN = 0;
-    int NAV_BAR_HIDDEN = 1;
-    int AUTO = -1;
-    int COLUMN_GAP_NORMAL = 32;
-    int COLUMN_COUNT_NORMAL = 1;
-    String MULTI_COLUMN = "multi-column";
-    String GRID = "grid";
-    String STICKY = "sticky";
-    String FIXED = "fixed";
-    String LEFT = "left";
-    String RIGHT = "right";
-    String CENTER = "center";
-    String BOLD = "bold";
-    String ITALIC = "italic";
-    String ORIGINAL = "original";
-    String LOW = "low";
-    String NORMAL = "normal";
-    String HIGH = "high";
-    String VISIBLE = "visible";
-    String HIDDEN = "hidden";
-    String TEXT = "text";
-    String PASSWORD = "password";
-    String TEL = "tel";
-    String EMAIL = "email";
-    String URL = "url";
-    String DATE = "date";
-    String TIME = "time";
-    String DATETIME = "datetime";
-    String PLAY = "play";
-    String PAUSE = "pause";
-    String STOP = "stop";
-    String DIRECTION_LEFT = "left";
-    String DIRECTION_RIGHT = "right";
-    String DIRECTION_UP = "up";
-    String DIRECTION_DOWN = "down";
-    String NUMBER = "number";
-
-    String NONE = "none";
-    String DEFAULT = "default";
-
-    String HORIZONTAL = "horizontal";
-  }
-
-  public interface Event {
-
-    String CLICK = "click";
-    String APPEAR = "appear";
-    String DISAPPEAR = "disappear";
-    String LOADMORE = "loadmore";
-    String FOCUS = "focus";
-    String BLUR = "blur";
-    String INPUT = "input";
-    String VIEWAPPEAR = "viewappear";
-    String VIEWDISAPPEAR = "viewdisappear";
-    String START = "start";
-    String PAUSE = "pause";
-    String FINISH = "finish";
-    String FAIL = "fail";
-    String ERROR = "error";
-    String RECEIVEDTITLE = "receivedtitle";
-    String PAGEFINISH = "pagefinish";
-    String PAGESTART = "pagestart";
-    String ONREFRESH = "refresh";
-    String ONLOADING = "loading";
-    String ONLOAD = "load";
-    String CHANGE = "change";
-    String ONPULLING_DOWN = "pullingdown";
-    String ONPULLING_UP = "pullingup";
-    String SCROLL = "scroll";
-    String SCROLL_START = "scrollstart";
-    String SCROLL_END = "scrollend";
-    String CLICKBACKITEM = "clickbackitem";
-    String RESUME_EVENT = "WXApplicationDidBecomeActiveEvent";
-    String PAUSE_EVENT = "WXApplicationWillResignActiveEvent";
-    String RETURN = "return";
-    String KEYBOARD = "keyboard";
-
-    String UNSTICKY = "unsticky";
-    String STICKY = "sticky";
-
-    String ON_TRANSITION_END = "transitionEnd";
-
-    String LAYEROVERFLOW = "layeroverflow";
-
-    interface SLOT_LIFECYCLE {
-      String CREATE = "create";
-      String ATTACH = "attach";
-      String DETACH = "detach";
-      String DESTORY = "destroy";
-    }
-
-    String STOP_PROPAGATION = "stopPropagation";
-    String STOP_PROPAGATION_RAX = "stoppropagation";
-    String ONMESSAGE = "message";
-    String NATIVE_BACK = "nativeback";
-  }
-
-  public interface PSEUDO {
-    String ACTIVE = ":active";
-    String ENABLED = ":enabled";
-    String DISABLED = ":disabled";
-    String FOCUS = ":focus";
-  }
-
-  public interface Scheme {
-
-    String FILE = "file";
-    String HTTPS = "https";
-    String HTTP = "http";
-    String LOCAL = "local";
-    String DATA = "data";
-  }
-
-  public interface CodeCache {
-    String URL = "bundleUrl";
-    String DIGEST = "bundleDigest";
-    String PATH = "codeCachePath";
-    String BANNER_DIGEST = "digest";
-    String SAVE_PATH = "v8";
-  }
-
-  public interface TimeFunction {
-    String LINEAR = "linear";
-    String EASE_IN_OUT = "ease-in-out";
-    String EASE_IN = "ease-in";
-    String EASE_OUT = "ease-out";
-    String EASE = "ease";
-    String CUBIC_BEZIER = "cubic-bezier";
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/Destroyable.java b/android/sdk/src/main/java/com/taobao/weex/common/Destroyable.java
deleted file mode 100644
index 5f5fa1c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/Destroyable.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-/**
- * Created by sospartan on 5/20/16.
- */
-public interface Destroyable {
-    public void destroy();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/ICheckBindingScroller.java b/android/sdk/src/main/java/com/taobao/weex/common/ICheckBindingScroller.java
deleted file mode 100644
index b90137a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/ICheckBindingScroller.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-/**
- * Created by zhengshihan on 2017/6/5.
- */
-
-public interface ICheckBindingScroller {
-  boolean isNeedScroller(String ref,Object option);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/IWXBridge.java b/android/sdk/src/main/java/com/taobao/weex/common/IWXBridge.java
deleted file mode 100755
index 479203d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/IWXBridge.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.bridge.ResultCallback;
-import com.taobao.weex.bridge.WXJSObject;
-import com.taobao.weex.bridge.WXParams;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import java.util.HashMap;
-import java.util.HashSet;
-
-/**
- * Bridge interface, native bridge and debug bridge both need to implement this interface
- */
-public interface IWXBridge extends IWXObject {
-
-  int DESTROY_INSTANCE = -1;
-  int INSTANCE_RENDERING = 1;
-  int INSTANCE_RENDERING_ERROR = 0;
-
-  /**
-   * init Weex
-   *
-   * @param framework assets/main.js
-   * @return
-   */
-  int initFramework(String framework, WXParams params);
-
-
-  /**
-   * init Weex
-   *
-   * @param framework assets/main.js
-   * @return
-   */
-  int initFrameworkEnv(String framework, WXParams params, String cacheDir, boolean pieSupport);
-
-
-  /**
-   * Update InitFramework Params
-   * */
-  void updateInitFrameworkParams(String key, String value, String desc);
-
-
-  void setLogType(float type, boolean isPerf);
-
-  void refreshInstance(String instanceId, String namespace, String function, WXJSObject[] args);
-
-  /**
-   * execute javascript function
-   */
-  int execJS(String instanceId, String namespace, String function, WXJSObject[] args);
-
-  /**
-   * execute javascript function with asynchronous callback
-   */
-  void execJSWithCallback(String instanceId, String namespace, String function, WXJSObject[] args, ResultCallback callback);
-
-  int execJSService(String javascript);
-
-  /**
-   * take the heap snapshot and serialize the heap to a local file.
-   *
-   * @param filename
-   */
-  void takeHeapSnapshot(String filename);
-
-  /**
-   * createInstance
-   * @param instanceId
-   * @param namespace
-   * @param function
-   * @param args
-   * @return
-   */
-  int createInstanceContext(String instanceId, String namespace, String function, WXJSObject[] args);
-
-  /**
-   * destoryInstance
-   * @param instanceId
-   * @param namespace
-   * @param function
-   * @param args
-   * @return
-   */
-  int destoryInstance(String instanceId, String namespace, String function, WXJSObject[] args);
-
-  /**
-   * execJSOnInstance
-   * @param instanceId
-   * @param script
-   * @param type
-   * @return
-   */
-  String execJSOnInstance(String instanceId, String script, int type);
-
-  /**
-   * js call native
-   */
-  int callNative(String instanceId, byte[] tasks, String callback);
-
-
-  int callNative(String instanceId, String tasks, String callback);
-
-  void reportJSException(String instanceId, String func, String exception);
-
-  Object callNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options);
-
-  void callNativeComponent(String instanceId, String ref, String method, byte[] arguments, byte[] options);
-
-  int callUpdateFinish(String instanceId, byte[] tasks, String callback);
-
-  int callRefreshFinish(String instanceId, byte[] tasks, String callback);
-
-  void reportServerCrash(String instanceId, String crashFile);
-
-
-  int callCreateBody(String instanceId, String componentType, String ref,
-                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
-                            float[] margins, float[] paddings, float[] borders);
-
-  int callAddElement(String instanceId, String componentType, String ref, int index, String parentRef,
-                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
-                            float[] margins, float[] paddings, float[] borders, boolean willLayout);
-
-  int callRemoveElement(String instanceId, String ref);
-
-  int callMoveElement(String instanceId, String ref, String parentref, int index);
-
-  int callAddEvent(String instanceId, String ref, String event);
-
-  int callRemoveEvent(String instanceId, String ref, String event);
-
-  int callUpdateStyle(String instanceId, String ref,
-                             HashMap<String, Object> styles,
-                             HashMap<String, String> paddings,
-                             HashMap<String, String> margins,
-                             HashMap<String, String> borders);
-
-  int callUpdateAttrs(String instanceId, String ref,
-                      HashMap<String, String> attrs);
-
-  int callAddChildToRichtext(String instanceId, String nodeType, String ref, String parentRef, String richTextRef,
-                             HashMap<String, String> styles, HashMap<String, String> attrs);
-
-  int callRemoveChildFromRichtext(String instanceId, String ref, String parentRef, String richTextRef);
-
-  int callUpdateRichtextStyle(String instanceId, String ref, HashMap<String, String> styles, String parentRef, String richTextRef);
-
-  int callUpdateRichtextChildAttr(String instanceId, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef);
-
-  int callLayout(String instanceId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index);
-
-  int callCreateFinish(String instanceId);
-
-  int callRenderSuccess(String instanceId);
-
-  int callAppendTreeCreateFinish(String instanceId, String ref);
-
-  int callHasTransitionPros(String instanceId, String ref, HashMap<String, String> styles);
-
-  ContentBoxMeasurement getMeasurementFunc(String instanceId, long renderObjectPtr);
-
-  void bindMeasurementToRenderObject(long ptr);
-
-  void setRenderContainerWrapContent(boolean wrap, String instanceId);
-
-  long[] getFirstScreenRenderTime(String instanceId);
-
-  long[] getRenderFinishTime(String instanceId);
-
-  void setDefaultHeightAndWidthIntoRootDom(String instanceId, float defaultWidth, float defaultHeight, boolean isWidthWrapContent, boolean isHeightWrapContent);
-
-  void onInstanceClose(String instanceId);
-
-  void forceLayout(String instanceId);
-
-  boolean notifyLayout(String instanceId);
-
-  void setStyleWidth(String instanceId, String ref, float value);
-
-  void setStyleHeight(String instanceId, String ref, float value);
-
-  void setMargin(String instanceId, String ref, CSSShorthand.EDGE edge, float value);
-
-  void setPadding(String instanceId, String ref, CSSShorthand.EDGE edge, float value);
-
-  void setPosition(String instanceId, String ref, CSSShorthand.EDGE edge, float value);
-
-  void markDirty(String instanceId, String ref, boolean dirty);
-
-  void setDeviceDisplay(String instanceId, float width, float height, float scale);
-
-  void registerCoreEnv(String key, String value);
-
-  void reportNativeInitStatus(String statusCode, String errorMsg);
-
-  void setTimeoutNative(String callbackId, String time);
-
-  void setJSFrmVersion(String version);
-
-  void resetWXBridge(boolean remoteDebug);
-
-  void setInstanceRenderType(String instanceId, String renderType);
-
-  void removeInstanceRenderType(String instanceId);
-
-  void setPageArgument(String instanceId, String key, String value);
-
-  void setViewPortWidth(String instanceId,float viewPortWidth);
-
-  void reloadPageLayout(String instanceId);
-
-  void setDeviceDisplayOfPage(String instanceId, float width, float height);
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/IWXDebugConfig.java b/android/sdk/src/main/java/com/taobao/weex/common/IWXDebugConfig.java
deleted file mode 100644
index 4833ef9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/IWXDebugConfig.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.bridge.WXDebugJsBridge;
-
-public interface IWXDebugConfig {
-
-  WXBridgeManager getWXJSManager();
-
-  WXDebugJsBridge getWXDebugJsBridge();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/IWXObject.java b/android/sdk/src/main/java/com/taobao/weex/common/IWXObject.java
deleted file mode 100644
index 6629040..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/IWXObject.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public interface IWXObject {
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/OnWXScrollListener.java b/android/sdk/src/main/java/com/taobao/weex/common/OnWXScrollListener.java
deleted file mode 100644
index af84d42..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/OnWXScrollListener.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-
-public interface OnWXScrollListener {
-
-  /**
-   * The  view is not currently scrolling.
-   */
-  int IDLE = RecyclerView.SCROLL_STATE_IDLE;
-  /**
-   * The view is currently being dragged by outside input such as user touch input.
-   */
-  int DRAGGING = RecyclerView.SCROLL_STATE_DRAGGING;
-  /**
-   * The view is currently animating to a final position while not under
-   * outside control.
-   */
-  int SETTLING = RecyclerView.SCROLL_STATE_SETTLING;
-
-  /**
-   * Callback method to be invoked when the view has been scrolled. This will be
-   * called after the scroll has completed.
-   * <p>
-   * This callback will also be called if visible item range changes after a layout
-   * calculation. In that case, dx and dy will be 0.
-   *
-   */
-  void onScrolled(View view, int x, int y);
-
-  /**
-   * Callback method to be invoked when view's scroll state changes.
-   *
-   */
-  void onScrollStateChanged(View view, int x, int y, int newState);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/RenderTypes.java b/android/sdk/src/main/java/com/taobao/weex/common/RenderTypes.java
deleted file mode 100644
index 0d7d83a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/RenderTypes.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public class RenderTypes {
-
-    public static final String RENDER_TYPE_NATIVE = "platform";
-
-    public static final String RENDER_TYPE_HERON = "heron";
-    public static final String RENDER_TYPE_HERON_URL_PARAM = "wx_heron=true";
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/TypeModuleFactory.java b/android/sdk/src/main/java/com/taobao/weex/common/TypeModuleFactory.java
deleted file mode 100644
index 636e325..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/TypeModuleFactory.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.bridge.MethodInvoker;
-import com.taobao.weex.bridge.ModuleFactory;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Use class
- * Created by sospartan on 6/17/16.
- */
-public class TypeModuleFactory<T extends WXModule> implements ModuleFactory<T> {
-  public static final String TAG = "TypeModuleFactory";
-  Class<T> mClazz;
-  Map<String, Invoker> mMethodMap;
-
-  public TypeModuleFactory(Class<T> clz) {
-    mClazz = clz;
-  }
-
-  private void generateMethodMap() {
-    if(WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d(TAG, "extractMethodNames:" + mClazz.getSimpleName());
-    }
-    HashMap<String, Invoker> methodMap = new HashMap<>();
-    try {
-      for (Method method : mClazz.getMethods()) {
-        // iterates all the annotations available in the method
-        for (Annotation anno : method.getDeclaredAnnotations()) {
-          if (anno != null) {
-            if(anno instanceof JSMethod) {
-              JSMethod methodAnnotation = (JSMethod) anno;
-              String name = JSMethod.NOT_SET.equals(methodAnnotation.alias())? method.getName():methodAnnotation.alias();
-              methodMap.put(name, new MethodInvoker(method, methodAnnotation.uiThread()));
-              break;
-            }else if(anno instanceof WXModuleAnno) {
-              WXModuleAnno methodAnnotation = (WXModuleAnno)anno;
-              methodMap.put(method.getName(), new MethodInvoker(method,methodAnnotation.runOnUIThread()));
-              break;
-            }
-          }
-        }
-      }
-    } catch (Throwable e) {
-      WXLogUtils.e("[WXModuleManager] extractMethodNames:", e);
-    }
-    mMethodMap = methodMap;
-  }
-
-
-  @Override
-  public T buildInstance() throws IllegalAccessException, InstantiationException {
-    return mClazz.newInstance();
-  }
-
-  @Override
-  public String[] getMethods() {
-    if (mMethodMap == null) {
-      generateMethodMap();
-    }
-    Set<String> keys = mMethodMap.keySet();
-    return keys.toArray(new String[keys.size()]);
-  }
-
-  @Override
-  public Invoker getMethodInvoker(String name) {
-    if (mMethodMap == null) {
-      generateMethodMap();
-    }
-    return mMethodMap.get(name);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXCompatModule.java b/android/sdk/src/main/java/com/taobao/weex/common/WXCompatModule.java
deleted file mode 100644
index 9b59d4a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXCompatModule.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.support.v4.content.LocalBroadcastManager;
-
-import com.taobao.weex.WXEnvironment;
-
-/**
- * Created by lixinke on 16/10/10.
- */
-
-public abstract class WXCompatModule extends WXModule implements Destroyable {
-
-  private ModuleReceive mModuleReceive;
-
-  public WXCompatModule() {
-    mModuleReceive = new ModuleReceive(this);
-    LocalBroadcastManager.getInstance(WXEnvironment.getApplication())
-        .registerReceiver(mModuleReceive, new IntentFilter(WXModule.ACTION_ACTIVITY_RESULT));
-    LocalBroadcastManager.getInstance(WXEnvironment.getApplication())
-        .registerReceiver(mModuleReceive, new IntentFilter(WXModule.ACTION_REQUEST_PERMISSIONS_RESULT));
-  }
-
-  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
-  }
-
-  public void onActivityResult(int requestCode, int resultCode, Intent data) {
-  }
-
-  @Override
-  public void destroy() {
-    LocalBroadcastManager.getInstance(WXEnvironment.getApplication())
-        .unregisterReceiver(mModuleReceive);
-  }
-
-  static class ModuleReceive extends BroadcastReceiver {
-
-    private WXCompatModule mWXCompatModule;
-
-    ModuleReceive(WXCompatModule module) {
-      mWXCompatModule = module;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-      String action = intent.getAction();
-      switch (action) {
-        case WXModule.ACTION_ACTIVITY_RESULT:
-          int requestCode = intent.getIntExtra(WXModule.REQUEST_CODE, -1);
-          int resultCode = intent.getIntExtra(WXModule.RESULT_CODE, Activity.RESULT_OK);
-          mWXCompatModule.onActivityResult(requestCode, resultCode, intent);
-          break;
-        case WXModule.ACTION_REQUEST_PERMISSIONS_RESULT:
-          requestCode = intent.getIntExtra(WXModule.REQUEST_CODE, -1);
-          String[] permissions = intent.getStringArrayExtra(WXModule.PERMISSIONS);
-          int[] grantResults = intent.getIntArrayExtra(WXModule.GRANT_RESULTS);
-          mWXCompatModule.onRequestPermissionsResult(requestCode, permissions, grantResults);
-          break;
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java b/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java
deleted file mode 100644
index 5fc6ef7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public interface WXConfig {
-
-  String os = "os";
-  String osName = "osName";
-  String appVersion="appVersion";
-  String cacheDir = "cacheDir";
-  String devId="devId";
-  String sysVersion="sysVersion";
-  String sysModel="sysModel";
-  String weexVersion="weexVersion";
-  String appName="appName";
-  String appGroup="appGroup";
-  String externalUserAgent="externalUserAgent";
-  String logLevel="logLevel";
-  String scale = "scale";
-  String layoutDirection = "layoutDirection";
-  String debugMode = "debugMode";
-  String androidStatusBarHeight = "androidStatusBarHeight";
-  String deviceHeight = "deviceHeight";
-  String deviceWidth = "deviceWidth";
-
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java b/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java
deleted file mode 100644
index 2434c12..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-
-public enum WXErrorCode {
-
-
-  /*
-   * environment
-   **/
-  /**
-   * Failure for load so library
-   */
-  WX_ERR_LOAD_SO("-2001", "load so error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * Failure for load JSLib
-   */
-  WX_ERR_LOAD_JSLIB("-2002", "unzip JSLib error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * So library corrupted
-   */
-  WX_ERR_BAD_SO("-2003", "so size error, to reload apk so",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * Failure for extract and copy so from apk
-   */
-  WX_ERR_COPY_FROM_APK("-2007", "system load so error,copy from APK also error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * jsBridge
-   **/
-  /**
-   * Error for JavaScript function parameter
-   */
-  WX_ERR_JSFUNC_PARAM("-2009", "JS params error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * Error for parsing JSON object
-   */
-  WX_ERR_JSON_OBJECT("-2008", "transform JSON->OBJ  error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * Failure for invoking JavaScript function
-   */
-  WX_ERR_INVOKE_NATIVE("-2012", "Native-> Call ->JS  error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * Failure for executing JavaScript function.
-   */
-  WX_ERR_JS_EXECUTE("-2013", "JavaScript execute error!",ErrorType.JS_ERROR,ErrorGroup.JS),
-
-
-  /*
-   * domModule
-   **/
-  WX_SUCCESS("0", "successful",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for createBody
-   */
-  WX_ERR_DOM_CREATEBODY("-2100", "createBody error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for updateAttrs
-   */
-  WX_ERR_DOM_UPDATEATTRS("-2101", "updateAttrs error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for updateAttr
-   */
-  WX_ERR_DOM_UPDATESTYLE("-2102", "updateStyle error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for addElement
-   */
-  WX_ERR_DOM_ADDELEMENT("-2103", "addElement error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for removeElement
-   */
-  WX_ERR_DOM_REMOVEELEMENT("-2104", "removeElement error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for moveElement
-   */
-  WX_ERR_DOM_MOVEELEMENT("-2105", "moveElement error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for addEvent
-   */
-  WX_ERR_DOM_ADDEVENT("-2106", "addEvent error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for removeEvent
-   */
-  WX_ERR_DOM_REMOVEEVENT("-2107", "removeEvent error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for invoking createFinish
-   */
-  WX_ERROR_DOM_CREATEFINISH("-2108", "createFinish error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for invoking refreshFinish
-   */
-  WX_ERROR_DOM_REFRESHFINISH("-2109", "refreshFinish error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Failure for scrollToElement
-   */
-  WX_ERR_DOM_SCROLLTO("-2110", "scrollToElement",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   *
-   */
-  WX_ERR_RELOAD_PAGE("-2111", "reloadPage",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_RELOAD_PAGE_EXCEED_LIMIT("-2114", "RELOAD_PAGE_EXCEED_LIMIT",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERROR_WHITE_SCREEN("-2116", "WHITE_SCREEN",ErrorType.RENDER_ERROR,ErrorGroup.JS),
-  WHITE_SCREEN_RESPONSE_TIMEOUT("-2117", "WHITE_SCREEN_RESPONSE_TIMEOUT",ErrorType.RENDER_ERROR,ErrorGroup.JS),
-  WHITE_SCREEN_REBOOT_EXCEED_LIMIT("-2118", "WHITE_SCREEN_REBOOT_EXCEED_LIMIT",ErrorType.RENDER_ERROR,ErrorGroup.JS),
-
-  /**
-   *
-   */
-  WX_ERR_JSC_CRASH("-2112", "weexjscCrash",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   *dom actions invalid for native
-   */
-  WX_ERR_FIRST_DOM_ACTION_EXCEPTION("-2113", "dom action is invalid ",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * JS Bundle download error
-   */
-
-  WX_ERR_JSDOWNLOAD_START("-2201", "js bundle download start",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_JSBUNDLE_DOWNLOAD("-2299", "js bundle download err",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_JSBUNDLE_EMPTY("-2203", "js bundle empty",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_JSDOWNLOAD_END("-2299", "js bundle download end",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  // for js framework
-  WX_JS_FRAMEWORK_INIT_SUCCESS("-1000", "js framework success",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_JS_FRAMEWORK_REINIT_SUCCESS("-1001", "js framework reinit success",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * JS Framework run error
-   */
-  WX_ERR_JS_FRAMEWORK("-1002", "js framework error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_JS_REINIT_FRAMEWORK("-1003", "js reinit framework error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * Single progress init error
-   */
-  WX_ERR_SINGLE_PROCESS_DLOPEN_FILE_NOT_EXIST("-1004", "so file does not exist",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_SINGLE_PROCESS_DLOPEN_FLAIED("-1005", "dlopen so file failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_SINGLE_PROCESS_DLSYM_FAILED("-1006", "find function from so file failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_ERR_SINGLE_PROCESS_JS_FRAMEWORK("-1007", "js framework  init singleProcess failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_JS_FRAMEWORK_INIT_MULPROCESS_FAILED("-1008", "js framework init multiProcess failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_JS_FRAMEWORK_REINIT_MULPROCESS_FAILED("-1009", "js framework reinit multiProcess failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_JS_FRAMEWORK_INIT_FAILED("-1010", "js framework init failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_JS_FRAMEWORK_INIT_SINGLE_PROCESS_SUCCESS("-1011", "js framework init success in single process",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL("-1012", "js framework init failed due to params null",ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_JS_FRAMEWORK_INIT_FAILED_FIND_ICU_TIMEOUT("-1013", "find icu failed",ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-
-  /**
-   * WX Key Exception Commit RT SDK Init
-   */
-  WX_KEY_EXCEPTION_SDK_INIT("-9000", "[WX_KEY_EXCEPTION_SDK_INIT]",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT("-9001", "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for android cpu is x86",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_SDK_INIT_TABLE_NOT_SUPPORT("-9002", "[WX_KEY_EXCEPTION_SDK_INIT_TABLE_NOT_SUPPORT] for device isTabletDevice",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_SDK_INIT_JSFM_INIT_FAILED("-9003", "[WX_KEY_EXCEPTION_SDK_INIT_JSFM_INIT_FAILED] for jsfm init failed|detail error is:",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * WX Key Exception Commit RT Register
-   */
-  WX_KEY_EXCEPTION_INVOKE_BRIDGE("-9100", "[WX_KEY_EXCEPTION_INVOKE_BRIDGE]",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED("-9101", "[WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE("-9102", "[WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES("-9103", "[WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT("-9104", "[WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-  /**
-   * WX Key Exception Commit Bundle Js Download
-   */
-  WX_KEY_EXCEPTION_JS_DOWNLOAD("-9200", "[WX_KEY_EXCEPTION_JS_DOWNLOAD]|",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED("-9201", "[WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED] | details",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * WX Key Exception Commit RT JsBridge eg. js excute runtime error
-   */
-  WX_KEY_EXCEPTION_WXBRIDGE("-9400", "[js excute runtime error] detail js stack -> ",ErrorType.JS_ERROR,ErrorGroup.JS),
-  WX_KEY_EXCEPTION_WXBRIDGE_EXCEPTION("-9401", "[js excute runtime error] detail js stack -> ",ErrorType.JS_ERROR,ErrorGroup.JS),
-
-  /**
-   * renderErrorCode
-   */
-  WX_RENDER_ERR_JS_CREATE_INSTANCE("-9600", "white screen cause create instance failed,check js stack ->",ErrorType.RENDER_ERROR,ErrorGroup.JS),
-  WX_RENDER_ERR_JS_CREATE_INSTANCE_CONTEXT("-9700", "white screen cause create instanceContext failed,check js stack ->",ErrorType.RENDER_ERROR,ErrorGroup.JS),
-  WX_RENDER_ERR_LAYER_OVERFLOW("-9602", "WX_RENDER_ERR_LAYER_OVERFLOW", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_RENDER_ERR_NULL_KEY("-9603", "WX_RENDER_ERR_NULL_KEY", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_RENDER_ERR_NATIVE_RUNTIME("-9604", "WX_RENDER_ERR for js error", ErrorType.RENDER_ERROR, ErrorGroup.NATIVE),
-  WX_RENDER_ERR_COMPONENT_NOT_REGISTER("-9605", "WX_RENDER_ERR_COMPONENT_NOT_REGISTER", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_RENDER_ERR_COMPONENT_ATTR_KEY("-9606", "The key passed to Component.updateAttr() is not string", ErrorType.NATIVE_ERROR, ErrorGroup.JS),
-  WX_RENDER_ERR_BRIDGE_ARG_NULL("-9610", "WX_RENDER_ERR_BRIDGE_ARG_NULL", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_RENDER_ERR_CONTAINER_TYPE("-9611", "WX_RENDER_ERR_CONTAINER_TYPE", ErrorType.JS_ERROR,ErrorGroup.JS),
-  WX_RENDER_ERR_TRANSITION("-9616", "WX_RENDER_ERR_TRANSITION", ErrorType.JS_ERROR, ErrorGroup.JS),
-  WX_RENDER_ERR_INSTANCE_ID_NULL("-9618", "WX_RENDER_ERR_INSTANCE_ID_NULL", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_RENDER_ERR_LIST_INVALID_COLUMN_COUNT("-9619", "WX_RENDER_ERR_LIST_INVALID_COLUMNJ_CONUNT", ErrorType.JS_ERROR, ErrorGroup.JS),
-  WX_RENDER_ERR_TEXTURE_SETBACKGROUND("-9620", "WX_RENDER_ERR_TEXTURE_SETBACKGROUND", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_RENDER_WAR_GPU_LIMIT_LAYOUT("-9621", "WX_RENDER_WAR_GPU_LIMIT_LAYOUT", ErrorType.JS_ERROR,ErrorGroup.JS),
-
-  WX_KEY_EXCEPTION_HERON("Heron_-9900", "Error of Heron engine: ", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
-  WX_KEY_EXCEPTION_HERON_RENDER("Heron_-9901", "Render error of Heron engine: ", ErrorType.RENDER_ERROR, ErrorGroup.NATIVE),
-
-  WX_KEY_EXCEPTION_NO_BUNDLE_TYPE("-9801", "Fatal Error : No bundle type in js bundle head, cause white screen or memory leak!!", ErrorType.JS_ERROR, ErrorGroup.JS),
-  /**
-   * degrade code.
-   */
-  WX_DEGRAD_ERR("-1000", "degradeToH5|Weex DegradPassivity ->",ErrorType.DEGRAD_ERROR,ErrorGroup.JS),
-
-  /**
-   * degrade for instance create failed, once this case occured,detail js stack and other specific
-   * cause need track into errmsg.
-   */
-  WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED("-1001", "degradeToH5|createInstance fail|wx_create_instance_error",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * degrade for network failed download js bundle.once this case occured,network requist response header
-   * and statuscode need track into errmsg.
-   */
-  WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED("-1002", "|wx_network_error|js bundle download failed",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * degrade for network failed for bundlejs is unbroken , once this case occured,network requist response header
-   * and statuscode need track into errmsg.
-   */
-  WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED("-1003", "degradeToH5|wx_network_error|js bundle content-length check failed",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * degrade for Response header Content-Type is null or not "application/javascript".
-   * once this case occured,network requist response header and statuscode need track into errmsg.
-   */
-  WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR("-1004", "degradeToH5|wx_user_intercept_error |Content-Type is not application/javascript, " +
-          "Weex render template must be javascript, please check your request!",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * degrade for other reason. such as white screen which block error for some unknown reason.
-   * once this case occured,detail msg need track.
-   */
-  WX_DEGRAD_ERR_OTHER_CAUSE_DEGRADTOH5("-1005", "degradeToH5|for other reason|",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
-
-
-  WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED_JS("-1006", "degradeToH5|createInstance fail|wx_create_instance_error",ErrorType.DEGRAD_ERROR,ErrorGroup.JS),
-
-  WX_DEGRAD_EAGLE_RENDER_ERROR ("Eagle_-1007", "degradeToH5|eagleRenderErr", ErrorType.DEGRAD_ERROR, ErrorGroup.NATIVE),
-
-  WX_ERR_HASH_MAP_TMP("-10010", "WX_ERR_HASH_MAP_TMP",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
-
-  /**
-   * TEST
-   */
-
-  WX_ERR_TEST("test", "test",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE);
-
-  private String errorCode;
-  private String errorMsg;
-  private String appendMsg="";
-  private String args;
-  private ErrorType mErrorType;
-  private ErrorGroup mErrorGroup;
-
-  WXErrorCode(String errorCode, String errorMsg,ErrorType errorType,ErrorGroup errorGroup) {
-    this.errorCode = errorCode;
-    this.errorMsg = errorMsg;
-    this.mErrorType = errorType;
-    this.mErrorGroup = errorGroup;
-  }
-
-  public void appendErrMsg(String err) {
-    appendMsg=err;
-  }
-
-  public String getErrorCode() {
-    return this.errorCode;
-  }
-
-  public String getErrorMsg() {
-    StringBuilder builder=new StringBuilder(errorMsg);
-    builder.append(appendMsg);
-    return builder.toString();
-  }
-
-  public ErrorType getErrorType() {
-    return mErrorType;
-  }
-
-  public ErrorGroup getErrorGroup() {
-    return mErrorGroup;
-  }
-
-  public String getArgs() {
-    return args;
-  }
-
-  public void setArgs(String args) {
-    this.args = args;
-  }
-
-  public enum ErrorType{
-    JS_ERROR,
-    NATIVE_ERROR,
-    RENDER_ERROR,
-    DEGRAD_ERROR,
-    DOWN_LOAD_ERROR
-  }
-
-  public enum ErrorGroup{
-    JS,
-    NATIVE
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXException.java b/android/sdk/src/main/java/com/taobao/weex/common/WXException.java
deleted file mode 100644
index 28d8da1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public class WXException extends Exception {
-
-  private static final long serialVersionUID = 7265837506862157379L;
-
-  public WXException(String msg) {
-    super(msg);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXImageSharpen.java b/android/sdk/src/main/java/com/taobao/weex/common/WXImageSharpen.java
deleted file mode 100644
index 8a6b38e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXImageSharpen.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public enum WXImageSharpen {
-  UNSHARPEN,
-  SHARPEN
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java b/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java
deleted file mode 100644
index 31524b2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import android.widget.ImageView;
-
-import com.taobao.weex.WXSDKInstance;
-
-import java.util.Map;
-
-public class WXImageStrategy {
-
-
-  /**
-   * <strong>Never!</strong>
-   * <strong>Never!</strong>
-   * <strong>Never!</strong>
-   * Never use this flag, ImageView has done all the job of clipping!
-   * There is no method to read this flag any more.
-   * This field will be removed when it's appropriate.
-   */
-  @Deprecated
-  public boolean isClipping;
-
-  /**
-   * Whether to sharp the image. The default is false.
-   */
-  public boolean isSharpen;
-
-  /**
-   * The blur radius of the image. 0 means no blur.
-   * */
-  public int blurRadius;
-
-  public String placeHolder;
-
-  /**
-   * running weex instanceId
-   * @see WXSDKInstance#mInstanceId
-   */
-  public String instanceId;
-
-  public WXImageStrategy()
-  {
-
-  }
-
-  public WXImageStrategy(String instanceId)
-  {
-    this.instanceId = instanceId;
-  }
-
-
-  public ImageListener getImageListener() {
-    return imageListener;
-  }
-
-  public void setImageListener(ImageListener imageListener) {
-    this.imageListener = imageListener;
-  }
-
-  ImageListener imageListener;
-
-  public interface ImageListener{
-    public void onImageFinish(String url,ImageView imageView,boolean  result,Map extra);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXInstanceWrap.java b/android/sdk/src/main/java/com/taobao/weex/common/WXInstanceWrap.java
deleted file mode 100644
index 46c6274..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXInstanceWrap.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.JSMethod;
-
-/**
- * Report template error.
- */
-public class WXInstanceWrap extends WXModule {
-
-  @JSMethod
-  public void error(String type, String code, String info) {
-    if (mWXSDKInstance != null) {
-      WXSDKInstance root = mWXSDKInstance;
-      if(info != null && info.contains("downgrade_to_root")){
-        while (root.getParentInstance() != null){
-          root = root.getParentInstance();
-        }
-      }
-      root.onRenderError(type + "|" + code, info);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXJSBridgeMsgType.java b/android/sdk/src/main/java/com/taobao/weex/common/WXJSBridgeMsgType.java
deleted file mode 100644
index 3a66e26..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXJSBridgeMsgType.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public class WXJSBridgeMsgType {
-
-  public static final int SET_TIMEOUT = 0x01;
-  public static final int NATIVE_CALL = 0x02;
-  public static final int FIRE_EVENT = 0x03;
-  public static final int CALLBACK = 0x04;
-  public static final int CALL_JS = 0x05;
-  public static final int CALL_JS_BATCH = 0x06;
-  public static final int INIT_FRAMEWORK = 0x07;
-  public static final int REGISTER_COMPONENTS = 0x08;
-  public static final int REGISTER_MODULES = 0x09;
-  public static final int REFRESH_INSTANCE = 0x0a;
-  public static final int MODULE_TIMEOUT = 0x0b;
-  public static final int MODULE_INTERVAL = 0x0c;
-  public static final int TAKE_HEAP_SNAPSHOT = 0x0d;
-
-  public static final int RELOAD_PAGE_NATIVE = 0x0e;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXJSEngineListener.java b/android/sdk/src/main/java/com/taobao/weex/common/WXJSEngineListener.java
deleted file mode 100644
index 10d2aec..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXJSEngineListener.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public interface WXJSEngineListener {
-
-  void createInstanceSuccess(String instanceId);
-
-  void destroyInstanceSuccess(String instanceId);
-
-  void createInstanceFailed(String instanceId);
-
-  void destroyInstanceFailed(String instanceId);
-
-  void fireEvent(boolean success, String instanceId, String ref, String type);
-
-  void callback(boolean success, String instanceId, String funcId, String data);
-
-  void initFramework(boolean success, String version, double jslibSize);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXJSExceptionInfo.java b/android/sdk/src/main/java/com/taobao/weex/common/WXJSExceptionInfo.java
deleted file mode 100644
index 105d224..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXJSExceptionInfo.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-
-import com.taobao.weex.WXEnvironment;
-
-import java.util.Map;
-
-public class WXJSExceptionInfo {
-
-  /**
-   * instance id
-   */
-  private String mInstanceId;
-  /**
-   * The URL where the exception occurred
-   */
-  private String mBundleUrl;
-  /**
-   * error code
-   */
-  private WXErrorCode mErrCode;
-  /**
-   * The function name of the exception
-   */
-  private String mFunction;
-  /**
-   * Exception details
-   */
-  private String mException;
-
-  /**
-   * Extended field
-   */
-  private Map<String,String> mExtParams;
-
-  /**
-   * weex sdk version
-   */
-  private String mWeexVersion = WXEnvironment.WXSDK_VERSION;
-
-  public long time;
-
-  /**
-   * js framework verison
-   */
-  private String mJsFrameworkVersion = WXEnvironment.JS_LIB_SDK_VERSION;
-
-  public WXJSExceptionInfo(String instanceId, String bundleUrl, WXErrorCode errCode, String function, String exception, Map<String,String> extParams) {
-    this.mInstanceId = instanceId;
-    this.mBundleUrl = bundleUrl;
-    this.mErrCode = errCode;
-    this.mFunction = function;
-    this.mException = exception;
-    this.mExtParams = extParams;
-    this.time = System.currentTimeMillis();
-  }
-
-  public String getInstanceId() {
-    return mInstanceId;
-  }
-
-  public void setInstanceId(String instanceId) {
-    mInstanceId = instanceId;
-  }
-
-  public String getBundleUrl() {
-    return mBundleUrl;
-  }
-
-  public void setBundleUrl(String bundleUrl) {
-    mBundleUrl = bundleUrl;
-  }
-
-  public WXErrorCode getErrCode() {
-    return mErrCode;
-  }
-
-  public void setErrCode(WXErrorCode errCode) {
-    mErrCode = errCode;
-  }
-
-  public String getFunction() {
-    return mFunction;
-  }
-
-  public void setFunction(String function) {
-    mFunction = function;
-  }
-
-  public String getException() {
-    return mException;
-  }
-
-  public void setException(String exception) {
-    mException = exception;
-  }
-
-  public Map<String, String> getExtParams() {
-    return mExtParams;
-  }
-
-  public void setExtParams(Map<String, String> extParams) {
-    mExtParams = extParams;
-  }
-
-  public String getWeexVersion() {
-    return mWeexVersion;
-  }
-
-
-  public String getJsFrameworkVersion() {
-    return mJsFrameworkVersion;
-  }
-
-
-  @Override
-  public String toString() {
-    return new StringBuilder()
-        .append(" errCode:").append(null == mErrCode?"unSetErrorCode":mErrCode.getErrorCode())
-        .append(",function:").append(null == mFunction?"unSetFuncName":mFunction)
-        .append(",exception:").append(null == mException?"unSetException":mException)
-        .toString();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXJSService.java b/android/sdk/src/main/java/com/taobao/weex/common/WXJSService.java
deleted file mode 100644
index 8cc4350..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXJSService.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class WXJSService implements IWXObject {
-    private String name;
-    private String script;
-    private Map<String, Object> options = new HashMap<>();
-
-    public String getName() { return name; }
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getScript() { return script; }
-    public void setScript(String script) {
-        this.script = script;
-    }
-
-    public Map<String, Object> getOptions() { return options; }
-    public void setOptions(Map<String, Object> options) {
-        this.options = options;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXModule.java b/android/sdk/src/main/java/com/taobao/weex/common/WXModule.java
deleted file mode 100644
index 2c029aa..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXModule.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import android.content.Intent;
-import android.text.TextUtils;
-import android.view.Menu;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * All modules must extend this class
- */
-public abstract class WXModule implements IWXObject {
-
-  public static final String ACTION_ACTIVITY_RESULT = "actionActivityResult";
-  public static final String ACTION_REQUEST_PERMISSIONS_RESULT = "actionRequestPermissionsResult";
-  public static final String REQUEST_CODE = "requestCode";
-  public static final String RESULT_CODE = "resultCode";
-  public static final String PERMISSIONS = "permissions";
-  public static final String GRANT_RESULTS = "grantResults";
-
-
-  public WXSDKInstance mWXSDKInstance;
-  private String mModuleName;
-
-
-  protected final WXComponent findComponent(String ref){
-    if(mWXSDKInstance != null && ref != null){
-      return WXSDKManager.getInstance()
-          .getWXRenderManager()
-          .getWXComponent(mWXSDKInstance.getInstanceId(), ref);
-    }
-    return null;
-  }
-
-  /** hook the Activity life cycle to Instance module**/
-  public void onActivityResult(int requestCode, int resultCode, Intent data){}
-
-  public void onActivityCreate(){}
-
-  public void onActivityStart(){}
-
-  public void onActivityPause(){}
-
-  public void onActivityResume(){}
-
-  public void onActivityStop(){}
-
-  public void onActivityDestroy(){}
-
-  public boolean onActivityBack() {return false;}
-
-  public boolean onCreateOptionsMenu(Menu menu){return false;}
-
-  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {}
-
-    /** end **/
-
-  private Map<String, List<String>> mEvents = new HashMap<>();
-  private Map<String, Boolean> mKeepAlives = new HashMap<>();
-
-
-
-  @JSMethod
-  public void addEventListener(String eventName, String callback, Map<String, Object> options) {
-    if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) {
-      return;
-    }
-    boolean isOnce = false;
-    if (options != null && options.size() > 0 && options.containsKey("once")) {
-      Object temp = options.get("once");
-      if (WXUtils.getBoolean(temp,false)) {
-        isOnce = true;
-      }
-    }
-    mKeepAlives.put(callback, isOnce);
-    if(mEvents.get(eventName)==null){
-      mEvents.put(eventName,new ArrayList<String>());
-    }
-    mEvents.get(eventName).add(callback);
-  }
-
-  @JSMethod
-  public void removeAllEventListeners(String eventName) {
-    if (mEvents.containsKey(eventName)) {
-      List<String> callbacks = mEvents.remove(eventName);
-      for(String callback:callbacks){
-        mKeepAlives.remove(callback);
-      }
-    }
-  }
-
-  /**
-   * Check whether the EventName has been registered
-   */
-  public List<String> getEventCallbacks(String eventName) {
-    return mEvents.get(eventName);
-  }
-
-  public boolean isOnce(String callback){
-    return mKeepAlives.get(callback);
-  }
-
-  public String getModuleName() {
-    return mModuleName;
-  }
-
-  public void setModuleName(String moduleName) {
-    mModuleName = moduleName;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXModuleAnno.java b/android/sdk/src/main/java/com/taobao/weex/common/WXModuleAnno.java
deleted file mode 100644
index 7812453..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXModuleAnno.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.annotation.JSMethod;
-
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/** Use {@link JSMethod} instead. **/
-@Retention(RetentionPolicy.RUNTIME)
-@Inherited
-@Deprecated
-public @interface WXModuleAnno {
-
-  @Deprecated
-  boolean moduleMethod() default true;
-
-  boolean runOnUIThread() default true;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXPerformance.java b/android/sdk/src/main/java/com/taobao/weex/common/WXPerformance.java
deleted file mode 100644
index aeb1ffb..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXPerformance.java
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import android.support.annotation.RestrictTo;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-@Deprecated
-public class WXPerformance {
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public enum Dimension {
-    JSLibVersion,
-    WXSDKVersion,
-    pageName,
-    spm,
-    scheme,
-    cacheType,
-    requestType,
-    networkType,
-    connectionType,
-    zcacheInfo,
-    wxContainerName,
-    wxInstanceType,
-    wxParentPage,
-    wxdim1,
-    wxdim2,
-    wxdim3,
-    wxdim4,
-    wxdim5,
-    bizType,
-    templateUrl,
-    useScroller
-  }
-
-  public enum Measure {
-    /**
-     * range : [min,max)
-     */
-    JSLibSize(0D, Double.MAX_VALUE),
-    //normal 300ms.. first install apk 30s ?
-    JSLibInitTime(0D, 80000D),
-    SDKInitTime(0D, 120000D),
-    SDKInitInvokeTime(0D, 5000D),
-    SDKInitExecuteTime(0D, 5000D),
-    JSTemplateSize(0D, 5000D),
-    pureNetworkTime(0D, 15000D),
-    networkTime(0D, 15000D),
-    fsCreateInstanceTime(0D, 3000D),
-    fsCallJsTotalTime(0D, 5000D),
-    fsCallJsTotalNum(0D, Double.MAX_VALUE),
-    fsCallNativeTotalTime(0D, 5000D),
-    fsCallNativeTotalNum(0D, Double.MAX_VALUE),
-    fsCallEventTotalNum(0D, Double.MAX_VALUE),
-    fsComponentCount(0D,100000D),
-    fsComponentCreateTime(0D,Double.MAX_VALUE),
-    fsRenderTime(0D, 5000D),
-    fsRequestNum(0D, 100D),
-    callCreateFinishTime(0D, 10000D),
-    cellExceedNum(0D, Double.MAX_VALUE),
-    communicateTotalTime(0D, 5000D),
-    maxDeepViewLayer(0D, Double.MAX_VALUE),
-    maxDeepVDomLayer(0D, Double.MAX_VALUE),
-    componentCount(0D, 1000000),
-    componentCreateTime(0D,Double.MAX_VALUE),
-    avgFps(0D, 61D),
-    timerCount(0D, Double.MAX_VALUE),
-
-    MaxImproveMemory(0D, Double.MAX_VALUE),
-    BackImproveMemory(0D, Double.MAX_VALUE),
-    PushImproveMemory(0D, Double.MAX_VALUE),
-    measureTime1(0D, Double.MAX_VALUE),
-    measureTime2(0D, Double.MAX_VALUE),
-    measureTime3(0D, Double.MAX_VALUE),
-    measureTime4(0D, Double.MAX_VALUE),
-    measureTime5(0D, Double.MAX_VALUE),
-
-    callBridgeTime(0D, Double.MAX_VALUE),
-    cssLayoutTime(0D, Double.MAX_VALUE),
-    parseJsonTime(0D, Double.MAX_VALUE),
-
-    communicateTime(0D, 5000D),
-    screenRenderTime(0D, 5000D),
-    totalTime(0D, 5000D),
-    localReadTime(0D, 5000D),
-    templateLoadTime(0D, 5000D),
-    packageSpendTime(0D, 5000D),
-    syncTaskTime(0D, 5000D),
-    actualNetworkTime(0D, 5000D),
-    firstScreenJSFExecuteTime(0D, 5000D),
-    //..
-
-    fluency(0D, 101D),
-    imgSizeCount(0D, 2000D),
-    interactionTime(0D,10000D),
-    interactionViewAddCount(0D, Double.MAX_VALUE),
-    interactionViewAddLimitCount(0D, Double.MAX_VALUE),
-    newFsRenderTime(0D, 10000D);
-
-    private double mMinRange, mMaxRange;
-
-    Measure(double min, double max) {
-      this.mMinRange = min;
-      this.mMaxRange = max;
-    }
-
-    public double getMinRange() {
-      return mMinRange;
-    }
-
-    public double getMaxRange() {
-      return mMaxRange;
-    }
-  }
-
-  public static final String DEFAULT = "default";
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-  public static final String CACHE_TYPE = "cacheType";
-
-  public static final int VIEW_LIMIT_HEIGHT = WXViewUtils.getScreenHeight() /3*2;
-  public static final int VIEW_LIMIT_WIDTH = WXViewUtils.getScreenWidth() /3*2;
-  public static boolean TRACE_DATA = WXEnvironment.isApkDebugable();
-
-  /**
-   * No longer needed.
-   */
-  @Deprecated
-  public String bizType = "weex";
-
-  /**
-   * Use {@link #pageName} instead.
-   */
-  @Deprecated
-  public String templateUrl;
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-  public String cacheType = "none";
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public long renderTimeOrigin;
-
-  public long renderUnixTimeOrigin;
-
-  public long fsRenderTime;
-
-  public long callCreateFinishTime;
-
-  public long interactionTime;
-
-  public long interactionRealUnixTime;
-
-  public int interactionViewAddCount;
-
-  public int interactionViewAddLimitCount;
-
-  public long newFsRenderTime;
-
-  public int localInteractionViewAddCount;
-
-  /**
-   * Time used for
-   * {@link com.taobao.weex.bridge.WXBridgeManager#createInstance(String, String, Map, String)}
-   */
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public long callCreateInstanceTime;
-
-
-  public long fsCallJsTotalTime;
-
-  public int fsCallJsTotalNum;
-
-  public long fsCallNativeTotalTime;
-
-  public int fsCallNativeTotalNum;
-
-  public int fsRequestNum;
-
-  public int fsComponentCount;
-
-  public int fsComponentCreateTime;
-
-  public int cellExceedNum;
-
-  public int timerInvokeCount;
-
-  public int fsCallEventTotalNum;
-
-  public long avgFPS;
-  public double fluency = 100D;
-
-  public long backImproveMemory;
-
-
-  /**
-   * Time spent for reading, time unit is ms.
-   */
-  public double localReadTime;
-
-  /**
-   * Name of the page
-   */
-  public String pageName = DEFAULT;
-
-  /**
-   * Size of JavaScript framework, the unit is KB
-   */
-  public double JSLibSize;
-
-  /**
-   * Time of initial JavaScript library
-   */
-  public long JSLibInitTime;
-
-  /**
-   * Size of JavaScript template
-   */
-  public double JSTemplateSize;
-
-  public long templateLoadTime;
-
-  /**
-   * Use {@link #callCreateInstanceTime} instead.
-   */
-  @Deprecated
-  public long communicateTime;
-
-  /**
-   * Time spent when rendering first screen
-   */
-  public long screenRenderTime;
-
-  /**
-   * Call native Time spent when rendering first screen
-   */
-  public long callBridgeTime;
-
-  /**
-   * Create Instance Time spent when rendering first screen
-   */
-  public long firstScreenJSFExecuteTime;
-
-  /**
-   * Call native Time spent when rendering first screen
-   */
-  public long parseJsonTime;
-
-  /**
-   * CssLayout Time spent when rendering first screen
-   */
-  public long cssLayoutTime;
-
-  /**
-   * Time spent, the unit is micro second
-   */
-  public double totalTime;
-
-  /**
-   * load bundle js time, unite ms
-   */
-  public long networkTime;
-
-  /**
-   * pure network time;
-   */
-  public long pureNetworkTime;
-
-  public long actualNetworkTime;
-  public long packageSpendTime;
-  public long syncTaskTime;
-  /**
-   * view hierarchy
-   */
-  public int maxDeepViewLayer;
-
-  public int maxDeepVDomLayer;
-
-  public double wrongImgSizeCount;
-
-  /**
-   * 1:true
-   * 0:false
-   */
-  public int useScroller = 0;
-
-  /**
-   * component Count
-   */
-  public long componentCount;
-
-  public long componentCreateTime;
-  /**
-   * Version of JavaScript libraray
-   */
-  public String JSLibVersion = WXEnvironment.JS_LIB_SDK_VERSION;
-
-  /**
-   * Version of Weex SDK
-   */
-  public String WXSDKVersion = WXEnvironment.WXSDK_VERSION;
-
-  /**
-   * The detail message of render failure
-   */
-  public String renderFailedDetail;
-
-  /**
-   * Error code
-   */
-  public String errCode;
-
-  /**
-   * Error message
-   */
-  @Deprecated
-  public String errMsg;
-  private StringBuilder mErrMsgBuilder;
-
-  public String args="";
-
-  public String connectionType;
-  public String requestType="other";
-
-  public String zCacheInfo;
-
-  /**
-   *for network tracker
-   */
-
-  /**
-   * TODO These dimensions will be moved to elsewhere
-   */
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  @Deprecated
-  public String wxDims[] = new String[5];
-
-  /**
-   * TODO These dimensions will be moved to elsewhere
-   */
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  @Deprecated
-  public long measureTimes[] = new long[5];
-
-
-  /**
-   * RenderAction
-   */
-  public int mActionAddElementCount = 0;
-  public int mActionAddElementSumTime = 0;
-
-  private String mInstanceId;
-
-  public WXPerformance(String instanceId){
-    mErrMsgBuilder=new StringBuilder();
-    mInstanceId = instanceId;
-  }
-
-  public Map<String, Double> getMeasureMap() {
-    double fsRenderTime;
-    if (this.fsRenderTime != 0) {
-      fsRenderTime = this.fsRenderTime - renderTimeOrigin;
-    } else {
-      if (totalTime != 0) {
-        fsRenderTime = totalTime;
-      } else {
-        fsRenderTime = -1;
-      }
-    }
-    Map<String, Double> quotas = new HashMap<>();
-    quotas.put(Measure.JSLibSize.toString(), JSLibSize);
-    quotas.put(Measure.JSLibInitTime.toString(), (double) JSLibInitTime);
-    quotas.put(Measure.SDKInitTime.toString(), (double) WXEnvironment.sSDKInitTime);
-    quotas.put(Measure.SDKInitInvokeTime.toString(), (double) WXEnvironment.sSDKInitInvokeTime);
-    quotas.put(Measure.SDKInitExecuteTime.toString(), (double) WXEnvironment.sSDKInitExecuteTime);
-    quotas.put(Measure.JSTemplateSize.toString(), JSTemplateSize);
-    quotas.put(Measure.pureNetworkTime.toString(), (double) pureNetworkTime);
-    quotas.put(Measure.networkTime.toString(), (double) networkTime);
-    quotas.put(Measure.fsCreateInstanceTime.toString(), (double) callCreateInstanceTime);
-    quotas.put(Measure.fsCallJsTotalTime.toString(), (double) fsCallJsTotalTime);
-    quotas.put(Measure.fsCallJsTotalNum.toString(), (double) fsCallJsTotalNum);
-    quotas.put(Measure.fsCallNativeTotalTime.toString(), (double) fsCallNativeTotalTime);
-    quotas.put(Measure.fsCallNativeTotalNum.toString(), (double) fsCallNativeTotalNum);
-    quotas.put(Measure.fsComponentCount.toString(),(double)fsComponentCount);
-    quotas.put(Measure.fsComponentCreateTime.toString(),(double)fsComponentCreateTime);
-    quotas.put(Measure.fsRenderTime.toString(), fsRenderTime);
-    quotas.put(Measure.fsRequestNum.toString(), (double) fsRequestNum);
-    quotas.put(Measure.communicateTotalTime.toString(), totalTime);
-    quotas.put(Measure.maxDeepViewLayer.toString(), (double) maxDeepViewLayer);
-    quotas.put(Measure.maxDeepVDomLayer.toString(), (double) maxDeepVDomLayer);
-    quotas.put(Measure.componentCount.toString(), (double) componentCount);
-    quotas.put(Measure.componentCreateTime.toString(),(double)componentCreateTime);
-    quotas.put(Measure.cellExceedNum.toString(), (double) cellExceedNum);
-    quotas.put(Measure.timerCount.toString(), (double) timerInvokeCount);
-    quotas.put(Measure.avgFps.toString(), (double) avgFPS);
-    quotas.put(Measure.fluency.toString(), fluency);
-    quotas.put(Measure.MaxImproveMemory.toString(), 0D);
-    quotas.put(Measure.BackImproveMemory.toString(), (double) backImproveMemory);
-    quotas.put(Measure.PushImproveMemory.toString(), 0D);
-
-    quotas.put(Measure.fsCallEventTotalNum.toString(), (double) fsCallEventTotalNum);
-    quotas.put(Measure.callCreateFinishTime.toString(), (double) callCreateFinishTime);
-    quotas.put(Measure.imgSizeCount.toString(), wrongImgSizeCount);
-    quotas.put(Measure.interactionTime.toString(), (double) interactionTime);
-    quotas.put(Measure.interactionViewAddCount.toString(), (double) interactionViewAddCount);
-    quotas.put(Measure.interactionViewAddLimitCount.toString(), (double) interactionViewAddLimitCount);
-    quotas.put(Measure.newFsRenderTime.toString(), (double) newFsRenderTime);
-
-    quotas.put(Measure.callBridgeTime.toString(), (double) callBridgeTime);
-    quotas.put(Measure.cssLayoutTime.toString(), (double) cssLayoutTime);
-    quotas.put(Measure.parseJsonTime.toString(), (double) parseJsonTime);
-
-    // TODO the following attribute is no longer needed and will be deleted soon.
-    quotas.put(Measure.screenRenderTime.toString(), (double) screenRenderTime);
-    quotas.put(Measure.communicateTime.toString(), (double) communicateTime);
-    quotas.put(Measure.localReadTime.toString(), localReadTime);
-    quotas.put(Measure.templateLoadTime.toString(), (double) templateLoadTime);
-    quotas.put(Measure.firstScreenJSFExecuteTime.toString(), (double) firstScreenJSFExecuteTime);
-    quotas.put(Measure.actualNetworkTime.toString(), (double) actualNetworkTime);
-    quotas.put(Measure.syncTaskTime.toString(), (double) syncTaskTime);
-    quotas.put(Measure.packageSpendTime.toString(), (double) packageSpendTime);
-
-    // TODO These attribute will be moved to elsewhere
-    quotas.put(Measure.measureTime1.toString(), (double) measureTimes[0]);
-    quotas.put(Measure.measureTime2.toString(), (double) measureTimes[1]);
-    quotas.put(Measure.measureTime3.toString(), (double) measureTimes[2]);
-    quotas.put(Measure.measureTime4.toString(), (double) measureTimes[3]);
-    quotas.put(Measure.measureTime5.toString(), (double) measureTimes[4]);
-    return quotas;
-  }
-
-  public Map<String, String> getDimensionMap() {
-    Map<String, String> quotas = new HashMap<>();
-    quotas.put(Dimension.JSLibVersion.toString(), JSLibVersion);
-    quotas.put(Dimension.WXSDKVersion.toString(), WXSDKVersion);
-    quotas.put(Dimension.pageName.toString(), pageName);
-    quotas.put(Dimension.requestType.toString(), requestType);
-    quotas.put(Dimension.networkType.toString(), "unknown");
-    quotas.put(Dimension.connectionType.toString(), connectionType);
-    quotas.put(Dimension.zcacheInfo.toString(), zCacheInfo);
-    quotas.put(Dimension.cacheType.toString(), cacheType);
-    quotas.put(Dimension.useScroller.toString(), String.valueOf(useScroller));
-
-    WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
-    String keyActivity = WXInstanceApm.KEY_PAGE_PROPERTIES_CONTAINER_NAME;
-    quotas.put(keyActivity, null == sdkInstance? "unKnow" : sdkInstance.getContainerInfo().get(keyActivity));
-    String keyType = WXInstanceApm.KEY_PAGE_PROPERTIES_INSTANCE_TYPE;
-    quotas.put(keyType,sdkInstance == null ?"unKnow": sdkInstance.getContainerInfo().get(keyType));
-    String keyParentPae = WXInstanceApm.KEY_PAGE_PROPERTIES_PARENT_PAGE;
-    quotas.put(keyParentPae,null == sdkInstance ?"unKnow":sdkInstance.getContainerInfo().get(keyParentPae));
-
-    // TODO These attribute will be moved to elsewhere
-    // Extra Dimension for 3rd developers.
-    quotas.put(Dimension.wxdim1.toString(), wxDims[0]);
-    quotas.put(Dimension.wxdim2.toString(), wxDims[1]);
-    quotas.put(Dimension.wxdim3.toString(), wxDims[2]);
-    quotas.put(Dimension.wxdim4.toString(), wxDims[3]);
-    quotas.put(Dimension.wxdim5.toString(), wxDims[4]);
-
-    // TODO the following attribute is no longer needed and will be deleted soon.
-    quotas.put(Dimension.bizType.toString(), bizType);
-    quotas.put(Dimension.templateUrl.toString(), templateUrl);
-    return quotas;
-  }
-
-  public static String[] getDimensions() {
-    List<String> ret = new LinkedList<>();
-    for (Dimension dimension : Dimension.values()) {
-      ret.add(dimension.toString());
-    }
-    return ret.toArray(new String[ret.size()]);
-  }
-
-  public static String[] getMeasures() {
-    List<String> ret = new LinkedList<>();
-    for (Measure measure : Measure.values()) {
-      ret.add(measure.toString());
-    }
-    return ret.toArray(new String[ret.size()]);
-  }
-
-  @Override
-  public String toString() {
-    if (WXEnvironment.isApkDebugable()) {
-      return "bizType:" + bizType + ",pageName:" + pageName + ",templateLoadTime" + templateLoadTime
-              + ",localReadTime:" + localReadTime + ",JSLibInitTime:" + JSLibInitTime
-              + ",JSLibSize:" + JSLibSize + ",templateUrl" + templateUrl
-              + ",JSTemplateSize:" + JSTemplateSize + ",communicateTime:" + communicateTime
-              + ",screenRenderTime:" + screenRenderTime
-              + ",firstScreenJSFExecuteTime:" + firstScreenJSFExecuteTime
-              + ",componentCount:" + componentCount
-              + ",syncTaskTime:" + syncTaskTime
-              + ",pureNetworkTime:" + pureNetworkTime
-              + ",networkTime:" + networkTime
-              + ",actualNetworkTime:" + actualNetworkTime
-              + ",packageSpendTime:" + packageSpendTime
-              + ",connectionType:" + connectionType
-              + ",requestType:" + requestType
-              + ",initInvokeTime:" + WXEnvironment.sSDKInitInvokeTime + ",initExecuteTime:" + WXEnvironment.sSDKInitExecuteTime
-              + ",SDKInitTime:" + WXEnvironment.sSDKInitTime
-              + ",totalTime:" + totalTime + ",JSLibVersion:" + JSLibVersion + ",WXSDKVersion:" + WXSDKVersion
-              + ",errCode:" + errCode + ",renderFailedDetail:" + renderFailedDetail
-              + ",arg:" + args
-              + ",errMsg:" + getErrMsg();
-    }
-    return super.toString();
-  }
-
-  public String getPerfData() {
-    return "networkTime:" + networkTime
-            + " actualNetworkTime:" + actualNetworkTime
-            + " connectionType:" + connectionType
-            + " requestType:" + requestType
-            + " firstScreenRenderTime:" + screenRenderTime
-            + " firstScreenJSFExecuteTime:" + firstScreenJSFExecuteTime
-            + " componentCount:" + componentCount
-            + " JSTemplateSize:" + JSTemplateSize
-            + " SDKInitTime:" + WXEnvironment.sSDKInitTime
-            + " totalTime:" + totalTime
-            + " JSLibVersion:" + JSLibVersion
-            + " WXSDKVersion:" + WXSDKVersion
-            + " pageName:" + pageName
-            + " useScroller:" + useScroller;
-
-  }
-
-  public String getErrMsg() {
-    return mErrMsgBuilder.toString();
-  }
-
-  public void appendErrMsg(CharSequence msg) {
-    mErrMsgBuilder.append(msg);
-  }
-
-  public void beforeInstanceRender(String instanceId) {
-    renderTimeOrigin = System.currentTimeMillis();
-    renderUnixTimeOrigin = WXUtils.getFixUnixTime();
-  }
-
-  public void afterInstanceDestroy(String instanceId) {
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXRefreshData.java b/android/sdk/src/main/java/com/taobao/weex/common/WXRefreshData.java
deleted file mode 100644
index bc01224..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXRefreshData.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public class WXRefreshData {
-
-  public String data;
-
-  public boolean isDirty;
-
-  public WXRefreshData(String data, boolean isDirty) {
-    this.data = data;
-    this.isDirty = isDirty;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXRenderStrategy.java b/android/sdk/src/main/java/com/taobao/weex/common/WXRenderStrategy.java
deleted file mode 100644
index 52ce118..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXRenderStrategy.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public enum WXRenderStrategy {
-  APPEND_ASYNC("APPEND_ASYNC"),
-  APPEND_ONCE("APPEND_ONCE"),
-  DATA_RENDER("DATA_RENDER"),
-  DATA_RENDER_BINARY("DATA_RENDER_BINARY"),
-  JSON_RENDER("JSON_RENDER");
-
-
-  private String flag;
-
-  WXRenderStrategy(String flag) {
-    this.flag = flag;
-  }
-
-  public String getFlag() {
-    return flag;
-  }
-}
-
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXRequest.java b/android/sdk/src/main/java/com/taobao/weex/common/WXRequest.java
deleted file mode 100644
index e266a96..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXRequest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.WXSDKInstance;
-
-import java.util.Map;
-
-public class WXRequest {
-
-  /**
-   * The request parameter
-   */
-  public Map<String, String> paramMap;
-
-  /**
-   * The request URL
-   */
-  public String url;
-  /**
-   * The request method
-   */
-  public String method;
-  /**
-   * The request body
-   */
-  public String body;
-
-  /**
-   * The request time out
-   */
-  public int timeoutMs = WXRequest.DEFAULT_TIMEOUT_MS;
-
-  /**
-   * The default timeout
-   */
-  public static final int DEFAULT_TIMEOUT_MS = 3000;
-
-  /**
-   * running weex instanceId
-   * @see WXSDKInstance#mInstanceId
-   */
-  public String instanceId;;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXRequestListener.java b/android/sdk/src/main/java/com/taobao/weex/common/WXRequestListener.java
deleted file mode 100644
index a9631dd..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXRequestListener.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-
-public interface WXRequestListener {
-
-  void onSuccess(int requestType, Object context, WXResponse response);
-
-  void onError(int requestType, Object context, WXResponse response);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXResponse.java b/android/sdk/src/main/java/com/taobao/weex/common/WXResponse.java
deleted file mode 100644
index f72eedb..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXResponse.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import java.util.Map;
-
-public class WXResponse {
-
-  /**
-   * Status code
-   */
-  public String statusCode;
-
-  /**
-   * Byte stream fetched from the connection
-   */
-  public String data;
-
-  public byte[] originalData;
-
-  /**
-   * Server internal error
-   */
-  public String errorCode;
-
-  /**
-   * Server error message
-   */
-  public String errorMsg;
-
-  /**
-   * Message for toast
-   */
-  public String toastMsg;
-
-  /**
-   * Parameter for further extension.
-   */
-  public Map<String, Object> extendParams;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXRuntimeException.java b/android/sdk/src/main/java/com/taobao/weex/common/WXRuntimeException.java
deleted file mode 100644
index 7063bdf..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXRuntimeException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-public class WXRuntimeException extends RuntimeException {
-
-  private static final long serialVersionUID = 5732315311747521491L;
-
-  public WXRuntimeException(String e) {
-    super(e);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXThread.java b/android/sdk/src/main/java/com/taobao/weex/common/WXThread.java
deleted file mode 100644
index f8afc56..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXThread.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.HandlerThread;
-import android.os.Message;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.tools.LogDetail;
-
-import java.lang.ref.WeakReference;
-
-import static com.taobao.weex.utils.tools.TimeCalculator.PLATFORM_ANDROID;
-
-/**
- * Thread used in weex
- */
-public class WXThread extends HandlerThread {
-
-  private Handler mHandler;
-
-  static class SafeRunnable implements Runnable {
-
-    static final String TAG = "SafeRunnable";
-    private LogDetail mTimelineLog = null;
-    private WeakReference<WXSDKInstance> mInstance;
-    final Runnable mTask;
-    SafeRunnable(Runnable task){
-      this(task,null);
-    }
-
-    SafeRunnable(Runnable task, String taskName){
-      this(task,null, taskName);
-    }
-
-    SafeRunnable(Runnable runnable, WXSDKInstance instance, String taskName) {
-      mTask = runnable;
-      if(taskName != null) {
-        mTimelineLog = new LogDetail();
-        mTimelineLog.info.platform = PLATFORM_ANDROID;
-        mTimelineLog.name(taskName);
-        mInstance = new WeakReference<>(instance);
-      }
-    }
-
-    @Override
-    public void run() {
-      try {
-        if(mTask != null) {
-          if (mTimelineLog != null)
-            mTimelineLog.taskStart();
-          mTask.run();
-          if (mTimelineLog != null)
-            mTimelineLog.taskEnd();
-        }
-      }catch (Throwable e){
-        //catch everything may throw from exection.
-        if(WXEnvironment.isApkDebugable()){
-          WXLogUtils.e(TAG,"SafeRunnable run throw expection:"+e.getMessage());
-          throw e;
-        }
-        WXLogUtils.w(TAG, e);
-      }
-
-      if (mTimelineLog != null) {
-        if(mInstance != null) {
-          WXSDKInstance wxsdkInstance = mInstance.get();
-          if(wxsdkInstance != null) {
-            wxsdkInstance.mTimeCalculator.addLog(mTimelineLog);
-          }
-        }
-      }
-
-    }
-  }
-
-  static class SafeCallback implements Callback {
-    static final String TAG = "SafeCallback";
-
-    final Callback mCallback;
-    SafeCallback(Callback cb){
-      mCallback = cb;
-    }
-
-    @Override
-    public boolean handleMessage(Message msg) {
-      boolean result = false;
-      try{
-        if(mCallback != null){
-          result = mCallback.handleMessage(msg);
-        }
-      }catch (Throwable e){
-        //catch everything may throw from exection.
-        if(WXEnvironment.isApkDebugable()){
-          WXLogUtils.e(TAG,"SafeCallback handleMessage throw expection:"+e.getMessage());
-          throw e;
-        }
-      }
-      return result;
-    }
-  }
-
-  /**
-   * Secure Runnable to prevent throw during execution.
-   * NOTE: DO NOT use this method to wrap runnable that may be removed by {@link Handler#removeCallbacks(Runnable)}
-   * @param runnable
-   * @return
-   */
-  public static Runnable secure(Runnable runnable){
-    return secure(runnable, null, null);
-  }
-
-
-  public static Runnable secure(Runnable runnable, WXSDKInstance instance, String runnableName){
-    if(runnable == null || runnable instanceof SafeRunnable){
-      return runnable;
-    }
-    return new SafeRunnable(runnable,instance, runnableName);
-  }
-
-  public static Callback secure(Callback callback){
-    if(callback == null || callback instanceof SafeCallback){
-      return callback;
-    }
-
-    return new SafeCallback(callback);
-  }
-
-  /**
-   * @param name name of thread
-   */
-  public WXThread(String name) {
-    super(name);
-    start();
-    mHandler = new Handler(getLooper());
-  }
-
-
-  public WXThread(String name, Callback callback) {
-    super(name);
-    start();
-    mHandler = new Handler(getLooper(), secure(callback));
-  }
-
-  /**
-   * @param name name of thread
-   * @param priority The priority to run the thread at. The value supplied must be from
-   *                 {@link android.os.Process} and not from java.lang.Thread.
-   */
-  public WXThread(String name, int priority, Callback callback) {
-    super(name, priority);
-    start();
-    mHandler = new Handler(getLooper(), secure(callback));
-  }
-
-  /**
-   * @param name name of thread
-   * @param priority The priority to run the thread at. The value supplied must be from
-   *                 {@link android.os.Process} and not from java.lang.Thread.
-   */
-  public WXThread(String name, int priority) {
-    super(name, priority);
-    start();
-    mHandler = new Handler(getLooper());
-  }
-
-  public Handler getHandler() {
-    return mHandler;
-  }
-
-  public boolean isWXThreadAlive() {
-    return (mHandler != null && getLooper() != null && isAlive());
-  }
-
-  @Override
-  public boolean quit() {
-    if (mHandler != null) {
-      mHandler.removeCallbacksAndMessages(null);
-    }
-    return super.quit();
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXWorkThreadManager.java b/android/sdk/src/main/java/com/taobao/weex/common/WXWorkThreadManager.java
deleted file mode 100644
index ed4df79..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXWorkThreadManager.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * Class for managing work thread.
- *
- * <p>
- *  This class is for internal purpose,
- *  please don't use it directly unless you know what you are doing.
- * </p>
- */
-@RestrictTo(Scope.LIBRARY_GROUP)
-public class WXWorkThreadManager {
-
-  private ExecutorService singleThreadExecutor;
-
-  public WXWorkThreadManager() {
-    singleThreadExecutor = Executors.newSingleThreadExecutor();
-  }
-
-  public void post(Runnable task) {
-    if (singleThreadExecutor != null)
-      singleThreadExecutor.execute(task);
-  }
-
-  /**
-   * Destroy current instance
-   */
-  public void destroy() {
-    if (singleThreadExecutor != null)
-      singleThreadExecutor.shutdown();
-    singleThreadExecutor = null;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/CSSConstants.java b/android/sdk/src/main/java/com/taobao/weex/dom/CSSConstants.java
deleted file mode 100755
index 221d046..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/CSSConstants.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-public class CSSConstants {
-
-  public static final float UNDEFINED = Float.NaN;
-
-  public static boolean isUndefined(float value) {
-    return Float.compare(value, UNDEFINED) == 0;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/CSSShorthand.java b/android/sdk/src/main/java/com/taobao/weex/dom/CSSShorthand.java
deleted file mode 100644
index 3037d99..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/CSSShorthand.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.text.TextUtils;
-import com.taobao.weex.dom.CSSShorthand.CSSProperty;
-import java.util.Arrays;
-
-public class CSSShorthand<T extends Enum<? extends CSSProperty>> implements Cloneable {
-
-  interface CSSProperty{
-  }
-
-  public static enum EDGE implements CSSProperty{
-    TOP, BOTTOM, LEFT, RIGHT, ALL;
-  }
-
-  public static enum CORNER implements CSSProperty{
-    BORDER_TOP_LEFT, BORDER_TOP_RIGHT,
-    BORDER_BOTTOM_RIGHT, BORDER_BOTTOM_LEFT, ALL;
-  }
-
-  public static enum TYPE {
-    MARGIN, PADDING, BORDER;
-  }
-
-  private float[] values;
-
-  public CSSShorthand(float []values){
-    replace(values);
-  }
-
-  public CSSShorthand() {
-    this(false);
-  }
-
-  CSSShorthand(boolean fillWithNaN) {
-    values = new float[Math.max(EDGE.values().length,CORNER.values().length)];
-    if (fillWithNaN) {
-      Arrays.fill(values, Float.NaN);
-    }
-  }
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public void set(@NonNull EDGE edge, float value){
-    setInternal(edge, value);
-  }
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public void set(@NonNull CORNER edge, float value) {
-    setInternal(edge, value);
-  }
-
-  /**
-   * {@link EDGE#ALL} is not supported, 0 will be returned.
-   * @throws IndexOutOfBoundsException
-   * @param edge
-   * @return
-   */
-  public float get(@NonNull EDGE edge){
-    return getInternal(edge);
-  }
-
-  /**
-   * {@link CORNER#ALL} is not supported, 0 will be returned.
-   * @throws IndexOutOfBoundsException
-   * @param edge
-   * @return
-   */
-  public float get(@NonNull CORNER edge) {
-    return getInternal(edge);
-  }
-
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public final void replace(float []values){
-    this.values = values;
-  }
-
-  @Override
-  public CSSShorthand clone() throws CloneNotSupportedException {
-    return (CSSShorthand) super.clone();
-  }
-
-  private void setInternal(@NonNull Enum<? extends CSSProperty> edge, float value){
-    if (edge == EDGE.ALL || edge == CORNER.ALL) {
-      Arrays.fill(values, value);
-    } else {
-      values[edge.ordinal()] = value;
-    }
-  }
-
-  private float getInternal(@NonNull Enum<? extends CSSProperty> edge){
-    return (edge == EDGE.ALL || edge == CORNER.ALL) ? 0 : values[edge.ordinal()];
-  }
-
-  @Override
-  @RestrictTo(Scope.LIBRARY)
-  public String toString() {
-    return TextUtils.isEmpty(values.toString()) ? "" : Arrays.toString(values);
-  }
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/RenderContext.java b/android/sdk/src/main/java/com/taobao/weex/dom/RenderContext.java
deleted file mode 100644
index 635039f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/RenderContext.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by sospartan on 23/02/2017.
- */
-
-public interface RenderContext {
-  WXSDKInstance getInstance();
-  WXComponent getComponent(String ref);
-  WXComponent unregisterComponent(String ref);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/TextDecorationSpan.java b/android/sdk/src/main/java/com/taobao/weex/dom/TextDecorationSpan.java
deleted file mode 100644
index c7d2579..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/TextDecorationSpan.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-
-import android.support.annotation.NonNull;
-import android.text.TextPaint;
-import android.text.style.CharacterStyle;
-import android.text.style.UpdateAppearance;
-
-import com.taobao.weex.ui.component.WXTextDecoration;
-
-public class TextDecorationSpan extends CharacterStyle
-    implements UpdateAppearance {
-
-  private final WXTextDecoration mTextDecoration;
-
-  public TextDecorationSpan(@NonNull WXTextDecoration wxTextDecoration) {
-    this.mTextDecoration = wxTextDecoration;
-  }
-
-  @Override
-  public void updateDrawState(TextPaint tp) {
-    switch (mTextDecoration) {
-      case LINETHROUGH:
-        tp.setUnderlineText(false);
-        tp.setStrikeThruText(true);
-        break;
-      case UNDERLINE:
-        tp.setUnderlineText(true);
-        tp.setStrikeThruText(false);
-        break;
-      case NONE:
-        tp.setUnderlineText(false);
-        tp.setStrikeThruText(false);
-        break;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java
deleted file mode 100644
index 82f853f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.UiThread;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.Constants.Name;
-import com.taobao.weex.common.WXImageSharpen;
-import com.taobao.weex.dom.binding.ELUtils;
-import com.taobao.weex.dom.binding.WXStatement;
-import com.taobao.weex.el.parse.Parser;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import static com.taobao.weex.dom.binding.ELUtils.COMPONENT_PROPS;
-import static com.taobao.weex.dom.binding.ELUtils.EXCLUDES_BINDING;
-import static java.lang.Boolean.parseBoolean;
-
-/**
- * store value of component attribute
- *
- */
-public class WXAttr implements Map<String, Object>,Cloneable {
-
-  private static final long serialVersionUID = -2619357510079360946L;
-
-  /**
-   * static attrs
-   * */
-  private @NonNull Map<String, Object> attr;
-  private Map<String, Object> writeAttr;
-
-  /**
-   * dynamic binding attrs, can be null, only weex use
-   * */
-  private ArrayMap<String, Object>  mBindingAttrs;
-
-  /**
-   * dynamic binding statement for match, can be null, only weex use
-   * */
-  private WXStatement mStatement;
-
-  public WXAttr(){
-    attr = new HashMap<>();
-  }
-
-  public WXAttr(@NonNull Map<String,Object> standardMap) {
-    attr = standardMap;
-  }
-
-  public WXAttr(@NonNull Map<String,Object> standardMap, int extra){
-    attr = standardMap;
-  }
-
-  public static String getPrefix(Map<String, Object> attr) {
-    if (attr == null) {
-      return null;
-    }
-    Object src = attr.get(Constants.Name.PREFIX);
-    if (src == null) {
-      return null;
-    }
-    return src.toString();
-  }
-
-  public static String getSuffix(Map<String, Object> attr) {
-    if (attr == null) {
-      return null;
-    }
-    Object src = attr.get(Constants.Name.SUFFIX);
-    if (src == null) {
-      return null;
-    }
-    return src.toString();
-  }
-
-  /**
-   * Compatible with value、content
-   *
-   * @return
-   */
-  public static String getValue(Map<String, Object> attr) {
-    if (attr == null) {
-      return null;
-    }
-    Object src = attr.get(Constants.Name.VALUE);
-    if (src == null) {
-      src = attr.get("content");
-      if (src == null) {
-        return null;
-      }
-    }
-    return src.toString();
-  }
-
-  public WXImageQuality getImageQuality() {
-    Object obj = containsKey(Name.QUALITY) ? get(Name.QUALITY) : get(Name.IMAGE_QUALITY);
-    WXImageQuality imageQuality = WXImageQuality.AUTO;
-    String value;
-    if (obj != null && !TextUtils.isEmpty(value = obj.toString())) {
-      try {
-        imageQuality = WXImageQuality.valueOf(value.toUpperCase(Locale.US));
-      }catch (IllegalArgumentException e){
-        WXLogUtils.e("Image", "Invalid value image quality. Only low, normal, high, original are valid");
-      }
-    }
-    return imageQuality;
-  }
-
-  public WXImageSharpen getImageSharpen() {
-    Object obj = get(Constants.Name.SHARPEN);
-    if (obj == null) {
-      obj = get(Constants.Name.IMAGE_SHARPEN);
-    }
-    if (obj == null) {
-      return WXImageSharpen.UNSHARPEN;
-    }
-    String imageSharpen = obj.toString();
-    WXImageSharpen waImageSharpen = WXImageSharpen.UNSHARPEN;
-    if (imageSharpen.equals("sharpen")) {
-      waImageSharpen = WXImageSharpen.SHARPEN;
-    }
-
-    return waImageSharpen;
-  }
-
-  public String getImageSrc() {
-    Object src = get(Constants.Name.SRC);
-    if (src == null) {
-      return null;
-    }
-    return src.toString();
-  }
-
-  public boolean canRecycled() {
-    Object obj = get(Constants.Name.RECYCLE);
-    if (obj == null) {
-      return true;
-    }
-    try {
-      return parseBoolean(String.valueOf(obj));
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] recycle:", e);
-    }
-    return true;
-  }
-
-  public boolean showIndicators() {
-    Object obj = get(Constants.Name.SHOW_INDICATORS);
-    if (obj == null) {
-      return true;
-    }
-
-    try {
-      return parseBoolean(String.valueOf(obj));
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] showIndicators:", e);
-    }
-    return true;
-  }
-
-  public boolean autoPlay() {
-    Object obj = get(Constants.Name.AUTO_PLAY);
-    if (obj == null) {
-      return false;
-    }
-
-    try {
-      return parseBoolean(String.valueOf(obj));
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] autoPlay:", e);
-    }
-    return false;
-  }
-
-  public String getScope() {
-    Object src = get(Constants.Name.SCOPE);
-    if (src == null) {
-      return null;
-    }
-    return src.toString();
-  }
-  public String getLoadMoreRetry() {
-    Object src = get(Constants.Name.LOADMORERETRY);
-    if (src == null) {
-      return null;
-    }
-    return src.toString();
-  }
-
-  public String getLoadMoreOffset() {
-    Object src = get(Constants.Name.LOADMOREOFFSET);
-    if (src == null) {
-      return null;
-    }
-    return src.toString();
-  }
-
-  public String optString(String key){
-    if(containsKey(key)){
-      Object value = get(key);
-      if (value instanceof String) {
-        return (String) value;
-      } else if (value != null) {
-        return String.valueOf(value);
-      }
-    }
-    return "";
-  }
-
-  public boolean getIsRecycleImage() {
-    Object obj = get(Constants.Name.RECYCLE_IMAGE);
-    if (obj == null) {
-      return true;
-    }
-
-    try {
-      return parseBoolean(String.valueOf(obj));
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] recycleImage:", e);
-    }
-    return false;
-  }
-  public String getScrollDirection() {
-    Object scrollDirection = get("scrollDirection");
-    if (scrollDirection == null) {
-      return "vertical";
-    }
-    return scrollDirection.toString();
-  }
-
-  public int getOrientation() {
-    String direction = getScrollDirection();
-    if(!TextUtils.isEmpty(direction)){
-      if(direction.equals(Constants.Value.HORIZONTAL)){
-        return Constants.Orientation.HORIZONTAL;
-      }
-    }
-    Object value = get(Name.ORIENTATION);
-    if(value != null && Constants.Value.HORIZONTAL.equals(value.toString())){
-      return Constants.Orientation.HORIZONTAL;
-    }
-    return Constants.Orientation.VERTICAL;
-  }
-
-  public float getElevation(int viewPortW) {
-    Object obj = get(Constants.Name.ELEVATION);
-    float ret = Float.NaN;
-    if (obj != null) {
-      String number = obj.toString();
-      if (!TextUtils.isEmpty(number)) {
-        ret = WXViewUtils.getRealSubPxByWidth(WXUtils.getFloat(number),viewPortW);
-      } else {
-        ret = 0;
-      }
-    }
-    return ret;
-  }
-
-  public float getColumnWidth(){
-
-    Object obj = get(Constants.Name.COLUMN_WIDTH);
-    if (obj == null) {
-      return Constants.Value.AUTO;
-    }
-
-    String value = String.valueOf(obj);
-    if(Constants.Name.AUTO.equals(value)){
-      return Constants.Value.AUTO;
-    }
-
-    try {
-      float columnWidth = Float.parseFloat(value);
-      return columnWidth > 0 ? columnWidth : 0;
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] getColumnWidth:", e);
-    }
-    return Constants.Value.AUTO;
-  }
-
-  public int getColumnCount() {
-
-    Object obj = get(Constants.Name.COLUMN_COUNT);
-    if (obj == null) {
-      return Constants.Value.AUTO;
-    }
-
-    String value = String.valueOf(obj);
-    if(Constants.Name.AUTO.equals(value)){
-      return Constants.Value.AUTO;
-    }
-
-    try {
-      int columnCount = Integer.parseInt(value);
-      return columnCount > 0 ? columnCount : Constants.Value.AUTO;
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] getColumnCount:", e);
-      return Constants.Value.AUTO;
-    }
-  }
-
-  public float getColumnGap() {
-
-    Object obj = get(Constants.Name.COLUMN_GAP);
-    if (obj == null) {
-      return Constants.Value.COLUMN_GAP_NORMAL;
-    }
-
-    String value = String.valueOf(obj);
-    if (Constants.Name.NORMAL.equals(value)) {
-      return Constants.Value.COLUMN_GAP_NORMAL;
-    }
-
-    try {
-      float columnGap = Float.parseFloat(value);
-      return columnGap >= 0 ? columnGap : Constants.Value.AUTO;
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] getColumnGap:", e);
-    }
-    return Constants.Value.COLUMN_GAP_NORMAL;
-  }
-
-  public int getLayoutType(){
-    Object obj = get(Constants.Name.LAYOUT);
-    if (obj == null) {
-      return WXRecyclerView.TYPE_LINEAR_LAYOUT;
-    }
-
-    try {
-      switch(String.valueOf(obj)){
-        case Constants.Value.MULTI_COLUMN :
-          return  WXRecyclerView.TYPE_STAGGERED_GRID_LAYOUT;
-        case Constants.Value.GRID :
-          return  WXRecyclerView.TYPE_GRID_LAYOUT;
-        default:
-          return WXRecyclerView.TYPE_LINEAR_LAYOUT;
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[WXAttr] getLayoutType:", e);
-    }
-    return WXRecyclerView.TYPE_LINEAR_LAYOUT;
-  }
-
-
-  @Override
-  public boolean equals(Object o) {
-    return attr.equals(o);
-  }
-
-  @Override
-  public int hashCode() {
-    return attr.hashCode();
-  }
-
-  @Override
-  public void clear() {
-    attr.clear();
-  }
-
-  @Override
-  public boolean containsKey(Object key) {
-    return attr.containsKey(key);
-  }
-
-  @Override
-  public boolean containsValue(Object value) {
-    return attr.containsValue(value);
-  }
-
-  @NonNull
-  @Override
-  public Set<Entry<String, Object>> entrySet() {
-    return attr.entrySet();
-  }
-
-  @Override
-  public Object get(Object key) {
-    Map<String, Object> temp = writeAttr;
-    if (null != temp) {
-      Object obj = temp.get(key);
-      if (null != obj) {
-        return obj;
-      }
-    }
-    return attr.get(key);
-  }
-
-  @Override
-  public boolean isEmpty() {
-    return attr.isEmpty();
-  }
-
-  @NonNull
-  @Override
-  public Set<String> keySet() {
-    return attr.keySet();
-  }
-
-  @Override
-  public Object put(String key, Object value) {
-    if(addBindingAttrIfStatement(key, value)){
-      return null;
-    }
-    return attr.put(key,value);
-  }
-
-  @Override
-  public void putAll(Map<? extends String, ?> map) {
-    //this.attr.putAll(map);
-    if (this.writeAttr == null) {
-      this.writeAttr = new ArrayMap<>();
-    }
-    this.writeAttr.putAll(map);
-  }
-
-  @Override
-  public Object remove(Object key) {
-    return attr.remove(key);
-  }
-
-  @Override
-  public int size() {
-    return attr.size();
-  }
-
-  @NonNull
-  @Override
-  public Collection<Object> values() {
-    return attr.values();
-  }
-
-  /**
-   * can by null, in most contion without template list, the value is null
-   * */
-  public ArrayMap<String, Object> getBindingAttrs() {
-    return mBindingAttrs;
-  }
-
-  /**
-   * can by null, in most contion without template list, the value is null
-   * */
-  public WXStatement getStatement() {
-    return mStatement;
-  }
-
-
-  public void setBindingAttrs(ArrayMap<String, Object> mBindingAttrs) {
-    this.mBindingAttrs = mBindingAttrs;
-  }
-
-  public void setStatement(WXStatement mStatement) {
-    this.mStatement = mStatement;
-  }
-
-  public void parseStatements(){
-    if(this.attr != null){
-       this.attr = filterStatementsFromAttrs(this.attr);
-    }
-  }
-
-  /**
-   * filter dynamic state ment
-   * */
-  private Map<String, Object> filterStatementsFromAttrs(Map attrs) {
-    if(attrs == null || attrs.size() == 0){
-      return attrs;
-    }
-    Set<Map.Entry<String,Object>> entries = attrs.entrySet();
-    Iterator<Entry<String,Object>> it =  entries.iterator();
-    while (it.hasNext()){
-      Map.Entry<String,Object> entry = it.next();
-      if(COMPONENT_PROPS.equals(entry.getKey())){
-        Object blockValue = ELUtils.bindingBlock(entry.getValue());
-        entry.setValue(blockValue);
-        continue;
-      }
-      if(addBindingAttrIfStatement(entry.getKey(), entry.getValue())){
-        it.remove();
-      }
-    }
-    return attrs;
-  }
-
-  /**
-   * filter dynamic attrs and statements
-   * */
-  private boolean addBindingAttrIfStatement(String key, Object value) {
-    for(String exclude : EXCLUDES_BINDING){
-      if(key.equals(exclude)){
-        return  false;
-      }
-    }
-    if(ELUtils.isBinding(value)){
-      if(mBindingAttrs == null){
-        mBindingAttrs = new ArrayMap<String, Object>();
-      }
-      value = ELUtils.bindingBlock(value);
-      mBindingAttrs.put(key, value);
-      return  true;
-    }
-    if(WXStatement.WX_IF.equals(key)){
-      if(mStatement == null){
-        mStatement = new WXStatement();
-      }
-      if(value != null) {
-        mStatement.put(key, Parser.parse(value.toString()));
-      }
-      return  true;
-    }
-
-    if(WXStatement.WX_FOR.equals(key)){
-      if(mStatement == null){
-        mStatement = new WXStatement();
-      }
-      value = ELUtils.vforBlock(value);
-      if(value != null) {
-        mStatement.put(key, value);
-        return  true;
-      }
-    }
-
-    if(WXStatement.WX_ONCE.equals(key)){
-      if(mStatement == null){
-        mStatement = new WXStatement();
-      }
-      mStatement.put(key, true);
-    }
-    return  false;
-  }
-
-  public void skipFilterPutAll(Map<String,Object> attrs){
-    this.attr.putAll(attrs);
-  }
-
-  @UiThread
-  public void mergeAttr() {
-    if (null != this.writeAttr) {
-      this.attr.putAll(this.writeAttr);
-      this.writeAttr = null;
-    }
-  }
-
-  @Override
-  public WXAttr clone() {
-    WXAttr wxAttr = new WXAttr();
-    wxAttr.skipFilterPutAll(attr);
-    if (mBindingAttrs != null) {
-      wxAttr.mBindingAttrs = new ArrayMap<>(mBindingAttrs);
-    }
-    if (mStatement != null){
-      wxAttr.mStatement = new WXStatement(mStatement);
-    }
-    return wxAttr;
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  @Override
-  public String toString() {
-    return attr.toString();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXCustomStyleSpan.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXCustomStyleSpan.java
deleted file mode 100644
index d0c61fe..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXCustomStyleSpan.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import android.graphics.Typeface;
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-import com.taobao.weex.utils.TypefaceUtil;
-
-public class WXCustomStyleSpan extends MetricAffectingSpan {
-
-  private final int mStyle;
-  private final int mWeight;
-  private final String mFontFamily;
-
-  public WXCustomStyleSpan(int fontStyle, int fontWeight, String fontFamily) {
-    mStyle = fontStyle;
-    mWeight = fontWeight;
-    mFontFamily = fontFamily;
-  }
-
-  @Override
-  public void updateDrawState(TextPaint ds) {
-    TypefaceUtil.applyFontStyle(ds, mStyle, mWeight, mFontFamily);
-  }
-
-  @Override
-  public void updateMeasureState(TextPaint paint) {
-    TypefaceUtil.applyFontStyle(paint, mStyle, mWeight, mFontFamily);
-  }
-
-  /**
-   * Returns {@link Typeface#NORMAL} or {@link Typeface#ITALIC}.
-   */
-  public int getStyle() {
-    return (mStyle == WXStyle.UNSET ? 0 : mStyle);
-  }
-
-  /**
-   * Returns {@link Typeface#NORMAL} or {@link Typeface#BOLD}.
-   */
-  public int getWeight() {
-    return (mWeight == WXStyle.UNSET ? 0 : mWeight);
-  }
-
-  /**
-   * Returns the font family set for this StyleSpan.
-   */
-  public String getFontFamily() {
-    return mFontFamily;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java
deleted file mode 100644
index 5ee2456..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import android.support.v4.util.ArrayMap;
-
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.dom.binding.ELUtils;
-import com.taobao.weex.dom.binding.JSONUtils;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Store value of component event
- */
-public class WXEvent extends ArrayList<String> implements Serializable, Cloneable {
-
-  private static final long serialVersionUID = -8186587029452440107L;
-
-  /**
-   *  event data format
-   *  {
-   *  type: 'appear',
-   *  params: [
-   *  { '@binding': 'index' },
-   *   'static',
-   *   { '@binding': 'item.name' },
-   *  { '@binding': '$event' }
-   *  ]
-   *  }
-   * */
-  public static final String EVENT_KEY_TYPE = "type";
-  public static final String EVENT_KEY_ARGS = "params";
-
-
-  /**
-   * dynamic binding event args, can be null, only weex use
-   * */
-  private ArrayMap mEventBindingArgs;
-  private ArrayMap<String, List<Object>> mEventBindingArgsValues;
-
-
-  @Override
-  public void clear() {
-    if(mEventBindingArgs != null){
-      mEventBindingArgs.clear();
-    }
-    if(mEventBindingArgsValues != null){
-      mEventBindingArgsValues.clear();
-    }
-    super.clear();
-  }
-
-
-  public boolean remove(String o) {
-    if(mEventBindingArgs != null){
-      mEventBindingArgs.remove(o);
-    }
-    if(mEventBindingArgsValues != null){
-      mEventBindingArgsValues.remove(o);
-    }
-    return super.remove(o);
-  }
-
-  /**
-   * can by null
-   * */
-  public ArrayMap getEventBindingArgs() {
-    return mEventBindingArgs;
-  }
-
-
-  public ArrayMap<String, List<Object>> getEventBindingArgsValues() {
-    return mEventBindingArgsValues;
-  }
-
-
-  public void addEvent(Object event) {
-    if(event instanceof CharSequence){
-      if(JSONUtils.isJSON(event.toString())){
-        addEvent(JSONUtils.toJSON(event.toString()));
-        return;
-      }
-      String eventName = event.toString();
-      if(!contains(eventName)){
-        add(eventName);
-      }
-    }else if(event instanceof JSONObject){
-      JSONObject bindings = (JSONObject) event;
-      addBindingEvent(bindings);
-    }
-  }
-
-
-
-  public static String getEventName(Object event){
-    if(event instanceof CharSequence){
-      return event.toString();
-    }else if(event instanceof JSONObject){
-      JSONObject bindings = (JSONObject) event;
-      String eventName = bindings.getString(WXEvent.EVENT_KEY_TYPE);
-      return  eventName;
-    }
-    if(event == null){
-      return  null;
-    }
-    return  event.toString();
-  }
-
-
-  public void parseStatements() {
-     if(!isEmpty()){
-       for(int i=0; i<size(); i++){
-         String event =  get(i);
-         if(JSONUtils.isJSON(event)){
-           JSONObject object = JSONUtils.toJSON(event);
-           String eventName = addBindingEvent(object);
-           set(i, eventName);
-         }
-       }
-     }
-  }
-
-  private String addBindingEvent(JSONObject bindings){
-    String eventName = bindings.getString(WXEvent.EVENT_KEY_TYPE);
-    Object args = bindings.get(WXEvent.EVENT_KEY_ARGS);
-    if (eventName != null) {
-      addBindingArgsEvent(eventName, args);
-    }
-    return eventName;
-  }
-
-  private void addBindingArgsEvent(String eventName, Object args){
-    if(!contains(eventName)){
-      add(eventName);
-    }
-    if(args != null){
-      if(mEventBindingArgs == null){
-        mEventBindingArgs = new ArrayMap();
-      }
-      mEventBindingArgs.put(eventName, ELUtils.bindingBlock(args));
-    }
-  }
-
-  public void putEventBindingArgsValue(String event, List<Object> value){
-    if(mEventBindingArgsValues == null){
-      mEventBindingArgsValues = new ArrayMap();
-    }
-    if(value == null){
-      mEventBindingArgsValues.remove(event);
-    }else{
-      mEventBindingArgsValues.put(event, value);
-    }
-  }
-
-  @Override
-  public WXEvent clone() {
-    WXEvent event = new WXEvent();
-    event.addAll(this);
-    if(mEventBindingArgs != null) {
-      event.mEventBindingArgs = new ArrayMap(mEventBindingArgs);
-    }
-    event.mEventBindingArgsValues = null; //this should not be clone, it dynamic args
-    return  event;
-  }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXImageQuality.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXImageQuality.java
deleted file mode 100644
index 6cce8f4..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXImageQuality.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-public enum WXImageQuality {
-
-  ORIGINAL,
-
-  LOW,
-
-  NORMAL,
-
-  HIGH,
-
-  AUTO
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXLineHeightSpan.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXLineHeightSpan.java
deleted file mode 100644
index 6f58e45..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXLineHeightSpan.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import android.graphics.Paint;
-import android.text.style.LineHeightSpan;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.utils.WXLogUtils;
-
-public class WXLineHeightSpan implements LineHeightSpan{
-
-  private int lineHeight;
-  public WXLineHeightSpan(int lineHeight){
-    this.lineHeight=lineHeight;
-  }
-
-  @Override
-  public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) {
-    if(WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("LineHeight", text + " ; start " + start + "; end " + end + "; spanstartv "
-              + spanstartv + "; v " + v + "; fm " + fm);
-    }
-    int halfLeading=(lineHeight-(fm.descent-fm.ascent))/2;
-    fm.top-=halfLeading;
-    fm.bottom+=halfLeading;
-    fm.ascent-=halfLeading;
-    fm.descent+=halfLeading;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
deleted file mode 100644
index 17f549e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import android.graphics.Typeface;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.support.v4.util.ArrayMap;
-import android.text.Layout;
-import android.text.TextUtils;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.binding.ELUtils;
-import com.taobao.weex.ui.component.WXText;
-import com.taobao.weex.ui.component.WXTextDecoration;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Store value of component style
- *
- */
-public class WXStyle implements Map<String, Object>,Cloneable {
-
-  private static final long serialVersionUID = 611132641365274134L;
-  public static final int UNSET = -1;
-
-  @NonNull
-  private Map<String,Object> mStyles;
-
-  @Nullable
-  private Map<String,Map<String,Object>> mPesudoStyleMap;// clz_group:{styleMap}
-
-  @Nullable
-  private Map<String,Object> mPesudoResetStyleMap;
-
-  /**
-   * dynamic binding attrs, can be null, only weex use
-   * */
-  private ArrayMap<String, Object>  mBindingStyle;
-
-  public WXStyle(){
-    mStyles = new ArrayMap<>();
-  }
-
-  public WXStyle(Map<String, Object> styles){
-    this.mStyles = styles;
-    processPesudoClasses(this.mStyles);
-  }
-
-  public WXStyle(Map<String, Object> mStyles, boolean byPesudo) {
-    this();
-    this.putAll(mStyles, byPesudo);
-  }
-
-  @Nullable
-  public String getBlur() {
-    if(get(Constants.Name.FILTER) == null) {
-      return null;
-    }
-    return get(Constants.Name.FILTER).toString().trim();
-  }
-
-  /*
-   * text-decoration
-   **/
-  public static WXTextDecoration getTextDecoration(Map<String, Object> style) {
-    Object obj;
-    WXTextDecoration ret;
-    if (style == null || (obj = style.get(Constants.Name.TEXT_DECORATION)) == null) {
-      ret = WXTextDecoration.NONE;
-    } else {
-      String textDecoration = obj.toString();
-      switch (textDecoration) {
-        case "underline":
-          ret = WXTextDecoration.UNDERLINE;
-          break;
-        case "line-through":
-          ret = WXTextDecoration.LINETHROUGH;
-          break;
-        case "none":
-          ret = WXTextDecoration.NONE;
-          break;
-        default:
-          ret = WXTextDecoration.INVALID;
-          break;
-      }
-    }
-    return ret;
-  }
-
-  public static String getTextColor(Map<String, Object> style) {
-    if (style == null) {
-      return "";
-    }
-    Object temp = style.get(Constants.Name.COLOR);
-    return temp == null ? "" : temp.toString();
-  }
-
-  public static int getFontWeight(Map<String, Object> style) {
-    int typeface = android.graphics.Typeface.NORMAL;
-    if (style != null) {
-      Object temp = style.get(Constants.Name.FONT_WEIGHT);
-      if (temp != null) {
-        String fontWeight = temp.toString();
-        switch (fontWeight){
-          case "600":
-          case "700":
-          case "800":
-          case "900":
-          case Constants.Value.BOLD:
-            typeface=Typeface.BOLD;
-            break;
-        }
-      }
-    }
-    return typeface;
-  }
-
-  public static int getFontStyle(Map<String, Object> style) {
-    int typeface = android.graphics.Typeface.NORMAL;
-    if (style == null) {
-      return typeface;
-    }
-    Object temp = style.get(Constants.Name.FONT_STYLE);
-    if (temp == null) {
-      return typeface;
-    }
-    String fontWeight = temp.toString();
-    if (fontWeight.equals(Constants.Value.ITALIC)) {
-      typeface = android.graphics.Typeface.ITALIC;
-    }
-    return typeface;
-  }
-
-  public static int getFontSize(Map<String, Object> style,int viewPortW) {
-    if (style == null) {
-      return (int) WXViewUtils.getRealPxByWidth(WXText.sDEFAULT_SIZE,viewPortW);
-    }
-    int fontSize = WXUtils.getInt(style.get(Constants.Name.FONT_SIZE));
-    if (fontSize <= 0) {
-      fontSize = WXText.sDEFAULT_SIZE;
-    }
-    return (int) WXViewUtils.getRealPxByWidth(fontSize,viewPortW);
-  }
-
-  public static String getFontFamily(Map<String, Object> style) {
-    String fontFamily = null;
-    if (style != null) {
-      Object temp;
-      temp = style.get(Constants.Name.FONT_FAMILY);
-      if (temp != null) {
-        fontFamily = temp.toString();
-      }
-    }
-    return fontFamily;
-  }
-
-  public static Layout.Alignment getTextAlignment(Map<String, Object> style){
-    return getTextAlignment(style, false);
-  }
-
-  public static Layout.Alignment getTextAlignment(Map<String, Object> style, boolean isRTL){
-    Layout.Alignment alignment= isRTL ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL;
-    String textAlign= (String) style.get(Constants.Name.TEXT_ALIGN);
-    if(TextUtils.equals(Constants.Value.LEFT,textAlign)){
-      alignment= Layout.Alignment.ALIGN_NORMAL;
-    }
-    else if(TextUtils.equals(Constants.Value.CENTER,textAlign)){
-      alignment= Layout.Alignment.ALIGN_CENTER;
-    }
-    else if(TextUtils.equals(Constants.Value.RIGHT,textAlign)){
-      alignment= Layout.Alignment.ALIGN_OPPOSITE;
-    }
-    return alignment;
-  }
-
-  public static TextUtils.TruncateAt getTextOverflow(Map<String, Object> style){
-    TextUtils.TruncateAt truncateAt=null;
-    String ellipse = (String) style.get(Constants.Name.TEXT_OVERFLOW);
-    if(TextUtils.equals(Constants.Name.ELLIPSIS,ellipse)){
-      truncateAt = TextUtils.TruncateAt.END;
-    }
-    return truncateAt;
-  }
-
-  public static int getLines(Map<String, Object> style) {
-    return WXUtils.getInt(style.get(Constants.Name.LINES));
-  }
-
-  public static int getLineHeight(Map<String, Object> style,int viewPortW){
-    if (style == null) {
-      return UNSET;
-    }
-    int lineHeight = WXUtils.getInt(style.get(Constants.Name.LINE_HEIGHT));
-    if (lineHeight <= 0) {
-      lineHeight = UNSET;
-      return lineHeight;
-    }
-    return (int) WXViewUtils.getRealPxByWidth(lineHeight,viewPortW);
-  }
-
-  public float getBorderRadius() {
-    float temp = WXUtils.getFloat(get(Constants.Name.BORDER_RADIUS));
-    if (WXUtils.isUndefined(temp)) {
-      return Float.NaN;
-    }
-    return temp;
-  }
-
-  public String getBorderColor() {
-    Object color = get(Constants.Name.BORDER_COLOR);
-    return color == null ? null : color.toString();
-  }
-
-  public String getBorderStyle() {
-    Object borderStyle = get(Constants.Name.BORDER_STYLE);
-    return borderStyle == null ? null : borderStyle.toString();
-  }
-
-  public boolean isSticky() {
-    Object position = get(Constants.Name.POSITION);
-    if (position == null) {
-      return false;
-    }
-    return position.toString().equals(Constants.Value.STICKY);
-  }
-
-  public boolean isFixed() {
-    Object position = get(Constants.Name.POSITION);
-    if (position == null) {
-      return false;
-    }
-    return position.toString().equals(Constants.Value.FIXED);
-  }
-
-  public float getLeft() {
-    float temp = WXUtils.getFloat(get(Constants.Name.LEFT));
-    if (WXUtils.isUndefined(temp)) {
-      return Float.NaN;
-    }
-    return temp;
-  }
-
-  public float getRight() {
-    float temp = WXUtils.getFloat(get(Constants.Name.RIGHT));
-    if (WXUtils.isUndefined(temp)) {
-      return Float.NaN;
-    }
-    return temp;
-  }
-
-  public float getTop() {
-    float temp = WXUtils.getFloat(get(Constants.Name.TOP));
-    if (WXUtils.isUndefined(temp)) {
-      return Float.NaN;
-    }
-    return temp;
-  }
-
-  public float getBottom() {
-    float temp = WXUtils.getFloat(get(Constants.Name.BOTTOM));
-    if (WXUtils.isUndefined(temp)) {
-      return Float.NaN;
-    }
-    return temp;
-  }
-
-  /*
-   * others
-   **/
-  public String getBackgroundColor() {
-    Object temp = get(Constants.Name.BACKGROUND_COLOR);
-    return temp == null ? "" : temp.toString();
-  }
-
-  public int getTimeFontSize() {
-    int fontSize = WXUtils.getInt(get("timeFontSize"));
-    if (fontSize <= 0) {
-      fontSize = WXText.sDEFAULT_SIZE;
-    }
-    return fontSize;
-  }
-
-  public float getOpacity() {
-    Object object = get(Constants.Name.OPACITY);
-    float opacity = 1;
-    if (object == null) {
-      return opacity;
-    }
-    return WXUtils.getFloat(object);
-  }
-
-  public String getOverflow() {
-    Object obj = get(Constants.Name.OVERFLOW);
-    return obj == null ? Constants.Value.VISIBLE : obj.toString();
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    return mStyles.equals(o);
-  }
-
-  @Override
-  public int hashCode() {
-    return mStyles.hashCode();
-  }
-
-  @Override
-  public void clear() {
-    mStyles.clear();
-  }
-
-  @Override
-  public boolean containsKey(Object key) {
-    return mStyles.containsKey(key);
-  }
-
-  @Override
-  public boolean containsValue(Object value) {
-    return mStyles.containsValue(value);
-  }
-
-  @NonNull
-  @Override
-  public Set<Entry<String, Object>> entrySet() {
-    return mStyles.entrySet();
-  }
-
-  @Override
-  public Object get(Object key) {
-    return mStyles.get(key);
-  }
-
-  @Override
-  public boolean isEmpty() {
-    return mStyles.isEmpty();
-  }
-
-  @NonNull
-  @Override
-  public Set<String> keySet() {
-    return mStyles.keySet();
-  }
-
-  @Override
-  public Object put(String key, Object value) {
-    if(addBindingStyleIfStatement(key, value)){
-      return null;
-    }
-    return mStyles.put(key,value);
-  }
-
-  @Override
-  public void putAll(Map<? extends String, ?> map) {
-    this.mStyles.putAll(map);
-  }
-
-  /**
-   * Used by Dom Thread, new and update styles.
-   * @param map
-   * @param byPesudo
-   */
-  public void putAll(Map<? extends String, ?> map, boolean byPesudo) {
-    this.mStyles.putAll(map);
-    if (!byPesudo) {
-      processPesudoClasses(map);
-    }
-  }
-
-  public void updateStyle(Map<? extends String, ?> map, boolean byPesudo){
-      parseBindingStylesStatements(map);
-      putAll(map, byPesudo);
-  }
-
-
-  public Map<String, Object> getPesudoResetStyles() {
-    if(mPesudoResetStyleMap == null){
-      mPesudoResetStyleMap = new ArrayMap<>();
-    }
-    return mPesudoResetStyleMap;
-  }
-
-  public Map<String, Map<String, Object>> getPesudoStyles() {
-    if(mPesudoStyleMap == null){
-      mPesudoStyleMap = new ArrayMap<>();
-    }
-    return mPesudoStyleMap;
-  }
-
-  <T extends String, V> void processPesudoClasses(Map<T, V> styles) {
-    Map<String, Object> tempMap = null;
-    for(Map.Entry<T, V> entry:styles.entrySet()){
-      //Key Format: "style-prop:pesudo_clz1:pesudo_clz2"
-      String key = entry.getKey();
-      int i;
-      if ((i = key.indexOf(":")) > 0) {
-        initPesudoMapsIfNeed(styles);
-        String clzName = key.substring(i);
-        if (clzName.equals(Constants.PSEUDO.ENABLED)) {
-          //enabled, use as regular style
-          String styleKey = key.substring(0, i);
-          if(tempMap == null){
-            tempMap = new ArrayMap<>();
-          }
-          tempMap.put(styleKey, entry.getValue());
-          mPesudoResetStyleMap.put(styleKey, entry.getValue());
-          continue;
-        } else {
-          clzName = clzName.replace(Constants.PSEUDO.ENABLED, "");//remove ':enabled' which is ignored
-        }
-
-        Map<String, Object> stylesMap = mPesudoStyleMap.get(clzName);
-        if (stylesMap == null) {
-          stylesMap = new ArrayMap<>();
-          mPesudoStyleMap.put(clzName, stylesMap);
-        }
-        stylesMap.put(key.substring(0, i), entry.getValue());
-      }
-    }
-
-    if (tempMap != null && !tempMap.isEmpty()) {
-      this.mStyles.putAll(tempMap);
-    }
-  }
-
-  @Override
-  public Object remove(Object key) {
-    return mStyles.remove(key);
-  }
-
-  @Override
-  public int size() {
-    return mStyles.size();
-  }
-
-  @NonNull
-  @Override
-  public Collection<Object> values() {
-    return mStyles.values();
-  }
-
-
-
-  private void initPesudoMapsIfNeed(Map<? extends String, ?> styles){
-    if(mPesudoStyleMap == null){
-      mPesudoStyleMap = new ArrayMap<>();
-    }
-    if(mPesudoResetStyleMap == null){
-      mPesudoResetStyleMap = new ArrayMap<>();
-    }
-    if(mPesudoResetStyleMap.isEmpty()){
-      mPesudoResetStyleMap.putAll(styles);
-    }
-  }
-
-
-
-  public void  parseStatements(){
-    if(this.mStyles != null){
-      this.mStyles = parseBindingStylesStatements(this.mStyles);
-    }
-  }
-
-  /**
-   * filter dynamic state ment
-   * */
-  private Map<String, Object> parseBindingStylesStatements(Map styles) {
-    if(styles == null || styles.size() == 0){
-      return styles;
-    }
-    Set<Map.Entry<String,Object>> entries = styles.entrySet();
-    Iterator<Entry<String,Object>> it =  entries.iterator();
-    while (it.hasNext()){
-      Map.Entry<String,Object> entry = it.next();
-      if(addBindingStyleIfStatement(entry.getKey(), entry.getValue())){
-        if(mPesudoStyleMap != null){
-          mPesudoStyleMap.remove(entry.getKey());
-        }
-        if(mPesudoResetStyleMap != null){
-          mPesudoResetStyleMap.remove(entry.getKey());
-        }
-        it.remove();
-      }
-    }
-    return styles;
-  }
-
-  /**
-   * filter dynamic attrs and statements
-   * */
-  private boolean addBindingStyleIfStatement(String key, Object value) {
-    if(ELUtils.isBinding(value)){
-      if(mBindingStyle == null){
-        mBindingStyle = new ArrayMap<String, Object>();
-      }
-      value = ELUtils.bindingBlock(value);
-      mBindingStyle.put(key, value);
-      return  true;
-    }
-    return  false;
-  }
-
-  public ArrayMap<String, Object> getBindingStyle() {
-    return mBindingStyle;
-  }
-
-  @Override
-  public WXStyle clone(){
-    WXStyle style = new WXStyle();
-    style.mStyles.putAll(this.mStyles);
-    if(mBindingStyle != null){
-      style.mBindingStyle = new ArrayMap<>(mBindingStyle);
-    }
-    if(mPesudoStyleMap != null) {
-      style.mPesudoStyleMap = new ArrayMap<>();
-      for (Entry<String, Map<String, Object>> entry : this.mPesudoStyleMap.entrySet()) {
-        Map<String, Object> valueClone = new ArrayMap<>();
-        valueClone.putAll(entry.getValue());
-        style.mPesudoStyleMap.put(entry.getKey(), valueClone);
-      }
-    }
-
-    if(mPesudoResetStyleMap!=null) {
-      style.mPesudoResetStyleMap = new ArrayMap<>();
-      style.mPesudoResetStyleMap.putAll(this.mPesudoResetStyleMap);
-    }
-
-
-    return style;
-  }
-
-  @Override
-  @RestrictTo(Scope.LIBRARY)
-  public String toString() {
-    return mStyles.toString();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java b/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java
deleted file mode 100644
index 390b611..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom.binding;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.el.parse.Parser;
-import com.taobao.weex.el.parse.Token;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.Set;
-
-/**
- * util's for binding and statment
- * Created by jianbai.gbj on 2017/8/17.
- */
-public class ELUtils {
-
-    public static final String BINDING = "@binding";
-    /**
-     * sub template
-     * */
-    public static final String IS_COMPONENT_ROOT = "@isComponentRoot";
-
-
-    public static final String COMPONENT_PROPS = "@componentProps";
-
-    public static final  String[] EXCLUDES_BINDING = {"clickEventParams"};
-
-    /**
-     * @param value check object is binding expression
-     * */
-    public static boolean isBinding(Object value){
-        if(value instanceof JSONObject){
-            JSONObject  object = (JSONObject) value;
-            if(object.containsKey(BINDING)){
-                return  true;
-            }
-        }else if(value instanceof JSONArray){
-            JSONArray array = (JSONArray) value;
-            for(int i=0; i<array.size(); i++){
-                if(isBinding(array.get(i))){
-                    return  true;
-                }
-            }
-        }else if(value instanceof String){
-            return ((String) value).indexOf(BINDING) >= 0;
-        }
-        return  false;
-    }
-
-    /**
-     * parse binding code to block, enable fast execute
-     * */
-    public static Object bindingBlock(Object value){
-        if(value instanceof JSONObject){
-            JSONObject  object = (JSONObject) value;
-            if(object.containsKey(BINDING)){
-                Object binding = object.get(BINDING);
-                if(!(binding instanceof Token)){
-                    object.put(BINDING, Parser.parse(binding.toString()));
-                }
-            }
-            Set<String> keys = object.keySet();
-            for(Object propsKey : keys){
-                if(object.get(propsKey) instanceof  JSONObject
-                        && ((JSONObject)object.get(propsKey)).containsKey(BINDING)){
-                    JSONObject propsValue = (JSONObject) object.get(propsKey);
-                    Object binding = propsValue.get(BINDING);
-                    if(!(binding instanceof Token)){
-                        propsValue.put(BINDING, Parser.parse(binding.toString()));
-                    }
-                }
-            }
-        }else if(value instanceof JSONArray){
-            JSONArray array = (JSONArray) value;
-            for(int i=0; i<array.size(); i++){
-                bindingBlock(array.get(i));
-            }
-        }else if(value instanceof String){
-            String json = value.toString();
-            if(json.startsWith("{")){
-                return bindingBlock(JSON.parseObject(json));
-            }else if(json.startsWith("[")){
-                return bindingBlock(JSON.parseArray(json));
-            }
-        }
-        return  value;
-    }
-
-    public static Object vforBlock(Object vfor){
-        if(vfor instanceof  JSONObject){
-            if(((JSONObject) vfor).containsKey(WXStatement.WX_FOR_LIST)){
-                Object list = ((JSONObject) vfor).get(WXStatement.WX_FOR_LIST);
-                if(!(list instanceof Token)){
-                    ((JSONObject) vfor).put(WXStatement.WX_FOR_LIST, Parser.parse(list.toString()));
-                }
-            }
-        }else if(vfor instanceof  String){
-            return vforBlock(JSONObject.parseObject(vfor.toString()));
-        }else{
-            if(WXEnvironment.isApkDebugable()){
-                WXLogUtils.e("weex", "weex vfor is illegal " + vfor);
-            }
-        }
-        return vfor;
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/binding/JSONUtils.java b/android/sdk/src/main/java/com/taobao/weex/dom/binding/JSONUtils.java
deleted file mode 100644
index 30d72d5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/binding/JSONUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom.binding;
-
-import com.alibaba.fastjson.JSONObject;
-
-/**
- * Created by furture on 2018/5/8.
- */
-
-public class JSONUtils {
-
-
-    public static boolean isJSON(Object json){
-        if(json instanceof JSONObject){
-            return true;
-        }
-        if(json instanceof String){
-            return ((String) json).startsWith("{");
-        }
-        return false;
-    }
-
-    public static JSONObject toJSON(Object json){
-        if(json instanceof JSONObject){
-            return (JSONObject) json;
-        }
-        return JSONObject.parseObject(json.toString());
-    }
-
-
-    public static boolean isJSON(String json){
-        return json.startsWith("{");
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java b/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java
deleted file mode 100644
index 6a760cb..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom.binding;
-
-import android.support.v4.util.ArrayMap;
-import android.support.v4.util.SimpleArrayMap;
-
-/**
- * Created by furture on 2017/8/17.
- * statement expression for template list, like v-if v-for
- */
-public class WXStatement extends ArrayMap<String, Object> implements  Cloneable  {
-
-    /**
-     * v-for statement, like
-     * <code>
-     *     <div v-for="(item, i) in dataset.panels">
-     *     <text>{{i}}: {{item.name}}</text>
-     *     </div>
-     * </code>
-     * json command:
-     * <code>
-     *      attr: {
-     *          '[[repeat]]': {
-     *          '@expression': 'dataList',
-     *          '@index': 'index',
-     *          '@alias': 'item'
-     *         }
-     *      }
-     * </code>
-     * */
-    public static final String WX_FOR = "[[repeat]]";
-    public static final String WX_FOR_INDEX = "@index";
-    public static final String WX_FOR_ITEM = "@alias";
-    public static final String WX_FOR_LIST = "@expression";
-
-
-    /**
-     * v-if statement, like:
-     * <code>
-     *   <p v-if="male">Male</p>
-     * </code>
-     * json command
-     * attr: {
-     *      '[[match]]': 'condition'
-     *    }
-     * */
-    public static final String WX_IF = "[[match]]";
-
-
-    /**
-     * once statement
-     * */
-    public static final  String WX_ONCE = "[[once]]";
-
-    public WXStatement() {
-    }
-
-    public WXStatement(SimpleArrayMap map) {
-        super(map);
-    }
-
-    @Override
-    protected WXStatement clone(){
-        return new WXStatement(this);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/transition/WXTransition.java b/android/sdk/src/main/java/com/taobao/weex/dom/transition/WXTransition.java
deleted file mode 100644
index cc468bb..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/dom/transition/WXTransition.java
+++ /dev/null
@@ -1,762 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom.transition;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ArgbEvaluator;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Handler;
-import android.support.v4.util.ArrayMap;
-import android.support.v4.view.animation.PathInterpolatorCompat;
-import android.text.TextUtils;
-import android.util.Property;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.Constants;
-//import com.taobao.weex.dom.DOMActionContext;
-//import com.taobao.weex.dom.WXDomHandler;
-//import com.taobao.weex.dom.WXDomObject;
-//import com.taobao.weex.dom.flex.Spacing;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.ui.animation.BackgroundColorProperty;
-import com.taobao.weex.ui.animation.TransformParser;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.SingleFunctionParser;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Pattern;
-
-import static com.taobao.weex.common.Constants.TimeFunction.CUBIC_BEZIER;
-import static com.taobao.weex.common.Constants.TimeFunction.EASE;
-import static com.taobao.weex.common.Constants.TimeFunction.EASE_IN;
-import static com.taobao.weex.common.Constants.TimeFunction.EASE_IN_OUT;
-import static com.taobao.weex.common.Constants.TimeFunction.EASE_OUT;
-import static com.taobao.weex.common.Constants.TimeFunction.LINEAR;
-
-/**
- *   transition on dom thread
- *   transition-property: height;
- *   transition-duration: .3s;
- *   transition-delay: .05s;
- *   transition-timing-function: ease-in-out;
- *
- *   Created by furture on 2017/10/18.
- */
-public class WXTransition {
-
-    public static final  String TRANSITION_PROPERTY = "transitionProperty";
-    public static final  String TRANSITION_DURATION = "transitionDuration";
-    public static final  String TRANSITION_DELAY = "transitionDelay";
-    public static final  String TRANSITION_TIMING_FUNCTION = "transitionTimingFunction";
-
-    public static final  Pattern PROPERTY_SPLIT_PATTERN = Pattern.compile("\\||,");
-
-
-    /**
-     * layout animation property
-     * */
-    private static final Set<String> LAYOUT_PROPERTIES = new HashSet<>();
-    static {
-        LAYOUT_PROPERTIES.add(Constants.Name.WIDTH);
-        LAYOUT_PROPERTIES.add(Constants.Name.HEIGHT);
-        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_TOP);
-        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_BOTTOM);
-        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_LEFT);
-        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_RIGHT);
-        LAYOUT_PROPERTIES.add(Constants.Name.LEFT);
-        LAYOUT_PROPERTIES.add(Constants.Name.RIGHT);
-        LAYOUT_PROPERTIES.add(Constants.Name.TOP);
-        LAYOUT_PROPERTIES.add(Constants.Name.BOTTOM);
-        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_LEFT);
-        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_RIGHT);
-        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_TOP);
-        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_BOTTOM);
-    }
-
-    /**
-     * transform animation property, use android system animaton ability
-     * */
-    private static final Set<String> TRANSFORM_PROPERTIES = new HashSet<>();
-    static {
-        TRANSFORM_PROPERTIES.add(Constants.Name.OPACITY);
-        TRANSFORM_PROPERTIES.add(Constants.Name.BACKGROUND_COLOR);
-        TRANSFORM_PROPERTIES.add(Constants.Name.TRANSFORM);
-    }
-
-    private List<String> properties;
-    private Interpolator  interpolator;
-    private long  duration;
-    private long delay;
-    private WXComponent mWXComponent;
-    private Handler handler;
-    private ValueAnimator layoutValueAnimator;
-    private Map<String, Object> layoutPendingUpdates;
-    private ObjectAnimator transformAnimator;
-    private Map<String, Object> transformPendingUpdates;
-    private Runnable transitionEndEvent;
-    private Map<String, Object> targetStyles;
-    private Runnable animationRunnable;
-
-    private Runnable transformAnimationRunnable;
-    private volatile AtomicInteger lockToken = new AtomicInteger(0);
-
-
-    public WXTransition() {
-        this.properties = new ArrayList<>(4);
-        this.handler = new Handler();
-        this.layoutPendingUpdates = new ArrayMap<>();
-        this.transformPendingUpdates = new ArrayMap<>();
-        this.targetStyles = new ArrayMap<>();
-    }
-
-    /**
-     * create transition from map styles if style contains transitionProperty
-     * */
-    public static WXTransition fromMap(Map<String, Object> style, WXComponent component){
-        if(style.get(TRANSITION_PROPERTY) == null){
-            return  null;
-        }
-        String propertyString = WXUtils.getString(style.get(TRANSITION_PROPERTY), null);
-        if(propertyString == null){
-            return null;
-        }
-        WXTransition transition  = new WXTransition();
-        updateTransitionProperties(transition, propertyString);
-        if(transition.properties.isEmpty()){
-            return  null;
-        }
-        transition.duration = parseTimeMillis(style, TRANSITION_DURATION, 0);
-        transition.delay =  parseTimeMillis(style, TRANSITION_DELAY, 0);
-        transition.interpolator = createTimeInterpolator(WXUtils.getString(style.get(TRANSITION_TIMING_FUNCTION), null));
-        transition.mWXComponent = component;
-        return  transition;
-    }
-
-    /**
-     * check updates has transition property
-     * */
-    public boolean hasTransitionProperty(Map<String, Object> styles){
-        for(String property : properties){
-            if(styles.containsKey(property)){
-                return  true;
-            }
-        }
-        return false;
-    }
-
-    public void updateTranstionParams(Map<String, Object> updates){
-        if(updates.containsKey(TRANSITION_DELAY)){
-            mWXComponent.getStyles().put(TRANSITION_DELAY, updates.remove(TRANSITION_DELAY));
-            this.delay = parseTimeMillis(mWXComponent.getStyles(), TRANSITION_DELAY, 0);
-        }
-
-        if(updates.containsKey(TRANSITION_TIMING_FUNCTION) && updates.get(TRANSITION_TIMING_FUNCTION) != null){
-            mWXComponent.getStyles().put(TRANSITION_TIMING_FUNCTION, updates.remove(TRANSITION_TIMING_FUNCTION));
-            this.interpolator = createTimeInterpolator(mWXComponent.getStyles().get(TRANSITION_TIMING_FUNCTION).toString());
-        }
-
-        if(updates.containsKey(TRANSITION_DURATION)){
-            mWXComponent.getStyles().put(TRANSITION_DURATION, updates.remove(TRANSITION_DURATION));
-            this.duration = parseTimeMillis(mWXComponent.getStyles(), TRANSITION_DURATION, 0);
-        }
-
-        if(updates.containsKey(TRANSITION_PROPERTY)){
-            mWXComponent.getStyles().put(TRANSITION_PROPERTY, updates.remove(TRANSITION_PROPERTY));
-            updateTransitionProperties(this, WXUtils.getString(mWXComponent.getStyles().get(TRANSITION_PROPERTY), null));
-        }
-    }
-
-    /**
-     * start transition animation, updates maybe split two different updates,
-     * because javascript will send multi update on same transition, we assume that updates in 8ms is one transition
-     * */
-    public void  startTransition(Map<String, Object> updates){
-        synchronized (lockToken){
-            final View taregtView = getTargetView();
-            if(taregtView == null){
-                return;
-            }
-            final int token = lockToken.incrementAndGet();
-            for(String property : properties){
-                if(updates.containsKey(property)){
-                    Object targetValue = updates.remove(property);
-                    if(LAYOUT_PROPERTIES.contains(property)) {
-                        layoutPendingUpdates.put(property, targetValue);
-                    }else if(TRANSFORM_PROPERTIES.contains(property)){
-                        transformPendingUpdates.put(property, targetValue);
-                    }
-                }
-            }
-
-            int delay = WXUtils.getNumberInt(mWXComponent.getAttrs().get("actionDelay"), 16);
-            if(delay > duration){
-                delay = (int) duration;
-            }
-            if(animationRunnable != null) {
-                handler.removeCallbacks(animationRunnable);
-            }
-            animationRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    if(token == lockToken.get()) {
-                        doTransitionAnimation(token);
-                    }
-                    animationRunnable = null;
-                }
-            };
-            if(delay > 0){
-                handler.postDelayed(animationRunnable, delay);
-            }else{
-                animationRunnable.run();
-            }
-        }
-    }
-
-    /**
-     * doTransitionAnimation include transform and layout animation.
-     * 1. put pre transition updates from target style to dom style
-     * 2. do transform animation and layout animation
-     * */
-    private void  doTransitionAnimation(final  int token){
-        final View taregtView = getTargetView();
-        if(taregtView == null){
-            return;
-        }
-        if(targetStyles.size() > 0){
-            for(String property : properties){
-                if(!(LAYOUT_PROPERTIES.contains(property) || TRANSFORM_PROPERTIES.contains(property))){
-                    continue;
-                }
-                if(layoutPendingUpdates.containsKey(property)){
-                    continue;
-                }
-                if(transformPendingUpdates.containsKey(property)){
-                    continue;
-                }
-                synchronized (targetStyles){
-                    if(targetStyles.containsKey(property)){
-                        //reset pre transition style
-                        Object targetValue = targetStyles.remove(property);
-                        mWXComponent.getStyles().put(property, targetValue);
-//                        domObject.getStyles().put(property, targetValue);
-//                        WXComponent component = getComponent();
-//                        if(component != null && component.getDomObject() != null){
-//                            component.getDomObject().getStyles().put(property, targetValue);
-//                        }
-                    }
-                }
-            }
-        }
-
-
-
-        if(transitionEndEvent != null){
-            taregtView.removeCallbacks(transitionEndEvent);
-        }
-        if(transitionEndEvent == null && duration > Float.MIN_NORMAL){
-            transitionEndEvent = new Runnable(){
-                @Override
-                public void run() {
-                    transitionEndEvent = null;
-                    if(duration < Float.MIN_NORMAL){
-                        return;
-                    }
-                    if(mWXComponent != null && mWXComponent.getEvents().contains(Constants.Event.ON_TRANSITION_END)){
-                        mWXComponent.fireEvent(Constants.Event.ON_TRANSITION_END);
-                    }
-                }
-            };
-        }
-        if(transformAnimationRunnable != null) {
-            taregtView.removeCallbacks(transformAnimationRunnable);
-        }
-        transformAnimationRunnable = new Runnable() {
-            @Override
-            public void run() {
-                synchronized (lockToken) {
-                    if(token == lockToken.get()) {
-                        doPendingTransformAnimation(token);
-                    }
-                }
-            }
-        };
-        taregtView.post(transformAnimationRunnable);
-        doPendingLayoutAnimation();
-    }
-
-
-    /**
-     *  transform, opacity, backgroundcolor which not effect layout use android system animation in main thread.
-     * */
-    private void doPendingTransformAnimation(int token) {
-        if(transformAnimator != null){
-            transformAnimator.cancel();
-            transformAnimator = null;
-        }
-        if(transformPendingUpdates.size() == 0){
-            return;
-        }
-        final View taregtView = getTargetView();
-        if(taregtView == null){
-            return;
-        }
-        List<PropertyValuesHolder> holders = new ArrayList<>(8);
-        String transform  = WXUtils.getString(transformPendingUpdates.remove(Constants.Name.TRANSFORM), null);
-        if(!TextUtils.isEmpty(transform)){
-            Map<Property<View,Float>, Float>  properties = TransformParser.parseTransForm(mWXComponent.getInstanceId(), transform, (int)mWXComponent.getLayoutWidth(), (int)mWXComponent.getLayoutHeight(), mWXComponent.getViewPortWidth());
-            PropertyValuesHolder[]  transformHolders = TransformParser.toHolders(properties);
-            for(PropertyValuesHolder holder : transformHolders){
-                holders.add(holder);
-            }
-            synchronized (targetStyles) {
-                targetStyles.put(Constants.Name.TRANSFORM, transform);
-            }
-        }
-
-        for(String property : properties){
-            if(!TRANSFORM_PROPERTIES.contains(property)){
-                continue;
-            }
-            if(!transformPendingUpdates.containsKey(property)){
-                continue;
-            }
-            Object value = transformPendingUpdates.remove(property);
-            synchronized (targetStyles) {
-                targetStyles.put(property, value);
-            }
-            switch (property){
-                case Constants.Name.OPACITY:{
-                    holders.add(PropertyValuesHolder.ofFloat(View.ALPHA, taregtView.getAlpha(), WXUtils.getFloat(value, 1.0f)));
-                    taregtView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); //hardware or none has bug on some platform
-                }
-                break;
-                case Constants.Name.BACKGROUND_COLOR:{
-                    int fromColor = WXResourceUtils.getColor(WXUtils.getString(mWXComponent.getStyles().getBackgroundColor(), null), 0);
-                    int toColor = WXResourceUtils.getColor(WXUtils.getString(value, null), 0);
-                    if(WXViewUtils.getBorderDrawable(taregtView) != null){
-                        fromColor = WXViewUtils.getBorderDrawable(taregtView).getColor();
-                    }else if (taregtView.getBackground() instanceof ColorDrawable) {
-                        fromColor = ((ColorDrawable) taregtView.getBackground()).getColor();
-                    }
-                    holders.add(PropertyValuesHolder.ofObject(new BackgroundColorProperty(), new ArgbEvaluator(), fromColor,toColor));
-                }
-                break;
-                default:break;
-            }
-        }
-
-        if(token == lockToken.get()) {
-            transformPendingUpdates.clear();
-        }
-        transformAnimator =  ObjectAnimator.ofPropertyValuesHolder(taregtView, holders.toArray(new PropertyValuesHolder[holders.size()]));
-        transformAnimator.setDuration((long) duration);
-        if((long) delay > 0) {
-            transformAnimator.setStartDelay((long) delay);
-        }
-        if(interpolator != null) {
-            transformAnimator.setInterpolator(interpolator);
-        }
-        transformAnimator.addListener(new AnimatorListenerAdapter() {
-            boolean  hasCancel = false;
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                super.onAnimationCancel(animation);
-                hasCancel = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if(hasCancel){
-                    return;
-                }
-                super.onAnimationEnd(animation);
-                WXTransition.this.onTransitionAnimationEnd();
-            }
-        });
-        transformAnimator.start();
-    }
-
-
-    public void doPendingLayoutAnimation(){
-        if(layoutValueAnimator != null){
-            layoutValueAnimator.cancel();
-            layoutValueAnimator = null;
-        }
-        if(layoutPendingUpdates.size() == 0){
-            return;
-        }
-        PropertyValuesHolder[] holders = new PropertyValuesHolder[layoutPendingUpdates.size()];
-        int index = 0;
-        for(String property : properties){
-            if(!LAYOUT_PROPERTIES.contains(property)){
-                continue;
-            }
-            if(layoutPendingUpdates.containsKey(property)){
-                Object targetValue = layoutPendingUpdates.remove(property);
-                synchronized (targetStyles) {
-                    targetStyles.put(property, targetValue);
-                }
-                holders[index] = createLayoutPropertyValueHolder(property, targetValue);
-                index++;
-            }
-        }
-        layoutPendingUpdates.clear();
-        doLayoutPropertyValuesHolderAnimation(holders);
-    }
-
-
-    private PropertyValuesHolder createLayoutPropertyValueHolder(String property, Object value){
-        PropertyValuesHolder holder = null;
-        switch (property){
-            case Constants.Name.WIDTH:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.WIDTH, mWXComponent.getLayoutWidth(),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloat(value, 0.0f), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.HEIGHT:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.HEIGHT, mWXComponent.getLayoutHeight(),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloat(value, 0.0f), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.MARGIN_TOP:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_TOP,  mWXComponent.getMargin().get(CSSShorthand.EDGE.TOP),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.MARGIN_LEFT:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_LEFT,  mWXComponent.getMargin().get(CSSShorthand.EDGE.LEFT),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.MARGIN_RIGHT:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_RIGHT,  mWXComponent.getMargin().get(CSSShorthand.EDGE.RIGHT),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.MARGIN_BOTTOM:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_BOTTOM,  mWXComponent.getMargin().get(CSSShorthand.EDGE.BOTTOM),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.LEFT:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.LEFT,  mWXComponent.getLayoutPosition().getLeft(),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.RIGHT:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.RIGHT,  mWXComponent.getLayoutPosition().getRight(),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.BOTTOM:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.BOTTOM,  mWXComponent.getLayoutPosition().getBottom(),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.TOP:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.TOP,  mWXComponent.getLayoutPosition().getTop(),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.PADDING_TOP:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_TOP,  mWXComponent.getPadding().get(CSSShorthand.EDGE.TOP),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.PADDING_BOTTOM:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_BOTTOM,  mWXComponent.getPadding().get(CSSShorthand.EDGE.BOTTOM),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.PADDING_LEFT:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_LEFT,  mWXComponent.getPadding().get(CSSShorthand.EDGE.LEFT),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            case Constants.Name.PADDING_RIGHT:{
-                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_RIGHT,  mWXComponent.getPadding().get(CSSShorthand.EDGE.RIGHT),
-                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
-            }
-            break;
-            default:
-                break;
-        }
-        if(holder == null){
-            holder  = PropertyValuesHolder.ofFloat(property, 1, 1);
-        }
-        return  holder;
-    }
-
-    private void doLayoutPropertyValuesHolderAnimation(PropertyValuesHolder[] holders){
-        layoutValueAnimator = ValueAnimator.ofPropertyValuesHolder(holders);
-        layoutValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(final ValueAnimator animation) {
-                PropertyValuesHolder holders[] = animation.getValues();
-                for(PropertyValuesHolder holder : holders){
-
-                    final String property =  holder.getPropertyName();
-                    asynchronouslyUpdateLayout(mWXComponent, property, (Float) animation.getAnimatedValue(property));
-                }
-//                WXBridgeManager.getInstance().calculateLayoutPostToJSThread(mWXComponent.getInstanceId(), mWXComponent.getRef(), false);
-            }
-        });
-        layoutValueAnimator.addListener(new AnimatorListenerAdapter() {
-
-            boolean  hasCancel = false;
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                super.onAnimationCancel(animation);
-                hasCancel = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if(hasCancel){
-                    return;
-                }
-                super.onAnimationEnd(animation);
-                WXTransition.this.onTransitionAnimationEnd();
-            }
-        });
-        if(interpolator != null) {
-            layoutValueAnimator.setInterpolator(interpolator);
-        }
-        layoutValueAnimator.setStartDelay((long) (delay));
-        layoutValueAnimator.setDuration((long) (duration));
-        layoutValueAnimator.start();
-    }
-
-    @SuppressWarnings("unused")
-    public static void asynchronouslyUpdateLayout(WXComponent component, final String propertyName, final float propertyValue) {
-        if(component == null) {
-            return;
-        }
-        final String ref = component.getRef();
-        final String instanceId = component.getInstanceId();
-        if(TextUtils.isEmpty(ref) || TextUtils.isEmpty(instanceId)) {
-            return;
-        }
-
-        WXSDKManager.getInstance().getWXBridgeManager().post(new Runnable() {
-            @Override
-            public void run() {
-                switch (propertyName){
-                    case Constants.Name.WIDTH:{
-                        WXBridgeManager.getInstance().setStyleWidth(instanceId, ref, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.HEIGHT:{
-                        WXBridgeManager.getInstance().setStyleHeight(instanceId, ref, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.MARGIN_TOP:{
-                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.TOP, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.MARGIN_LEFT:{
-                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.LEFT, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.MARGIN_RIGHT:{
-                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.RIGHT, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.MARGIN_BOTTOM:{
-                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.BOTTOM, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.LEFT:{
-                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.LEFT, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.RIGHT:{
-                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.RIGHT, (propertyValue));
-                    }
-                    break;
-                    case Constants.Name.BOTTOM:{
-                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.BOTTOM, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.TOP:{
-                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.TOP, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.PADDING_TOP:{
-                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.TOP, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.PADDING_BOTTOM:{
-                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.BOTTOM, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.PADDING_LEFT:{
-                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.LEFT, propertyValue);
-                    }
-                    break;
-                    case Constants.Name.PADDING_RIGHT:{
-                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.RIGHT, propertyValue);
-                    }
-                    break;
-                    default:
-                        break;
-                }
-            }
-        });
-    }
-
-    private synchronized void onTransitionAnimationEnd(){
-        if(duration > 0){
-            if(transitionEndEvent != null){
-                View view = getTargetView();
-                if(view != null &&  transitionEndEvent != null){
-                    view.post(transitionEndEvent);
-                }
-                transitionEndEvent = null;
-            }
-        }
-        synchronized (targetStyles){
-            if(targetStyles.size() > 0){
-                for(String property : properties) {
-                    if(targetStyles.containsKey(property)){
-                        Object targetValue = targetStyles.remove(property);
-                        mWXComponent.getStyles().put(property, targetValue);
-                    }
-                }
-                targetStyles.clear();
-            }
-        }
-    }
-
-    private View getTargetView(){
-        return null != mWXComponent ? mWXComponent.getHostView() : null;
-    }
-
-
-    /**
-     * get time millis
-     * */
-    private static long parseTimeMillis(Map<String, Object> style, String key, long defaultValue){
-        String  duration = WXUtils.getString(style.get(key), null);
-        if(duration != null){
-            duration = duration.replaceAll("ms", "");
-        }
-        if(duration != null){
-            if(WXEnvironment.isApkDebugable()){
-                if(duration.contains("px")){
-                    WXLogUtils.w("Transition Duration Unit Only Support ms, " + duration + " is not ms Unit");
-                }
-            }
-            duration = duration.replaceAll("px", "");
-        }
-        if(TextUtils.isEmpty(duration)){
-            return  defaultValue;
-        }
-        try{
-            return (long)Float.parseFloat(duration);
-        }catch (NumberFormatException e){
-            return  defaultValue;
-        }
-    }
-
-    /**
-     * create interpolcator same with web
-     * http://www.w3school.com.cn/cssref/pr_transition-timing-function.asp
-     * */
-    private static Interpolator createTimeInterpolator(String interpolator) {
-        if (!TextUtils.isEmpty(interpolator)) {
-            switch (interpolator) {
-                case EASE_IN:
-                    return PathInterpolatorCompat.create(0.42f,0f, 1f,1f);
-                case EASE_OUT:
-                    return PathInterpolatorCompat.create(0f,0f, 0.58f,1f);
-                case EASE_IN_OUT:
-                    return PathInterpolatorCompat.create(0.42f,0f, 0.58f,1f);
-                case EASE:
-                    return PathInterpolatorCompat.create(0.25f,0.1f, 0.25f,1f);
-                case LINEAR:
-                    return PathInterpolatorCompat.create(0.0f,0f, 1f,1f);
-                default:
-                    try {
-                        //Parse cubic-bezier
-                        SingleFunctionParser<Float> parser = new SingleFunctionParser<>(
-                                interpolator,
-                                new SingleFunctionParser.FlatMapper<Float>() {
-                                    @Override
-                                    public Float map(String raw) {
-                                        return Float.parseFloat(raw);
-                                    }
-                                });
-                        List<Float> params = parser.parse(CUBIC_BEZIER);
-                        if (params != null && params.size() == 4) {
-                            return PathInterpolatorCompat.create(
-                                    params.get(0), params.get(1), params.get(2), params.get(3));
-                        }
-                    } catch (RuntimeException e) {
-                        if(WXEnvironment.isApkDebugable()) {
-                            WXLogUtils.e("WXTransition", e);
-                        }
-                    }
-            }
-        }
-        return PathInterpolatorCompat.create(0.25f,0.1f, 0.25f,1f);
-    }
-
-    private static  void  updateTransitionProperties(WXTransition transition, String transtionProperty){
-        if(transtionProperty == null){
-            return;
-        }
-        transition.properties.clear();
-        String[] propertiesArray = PROPERTY_SPLIT_PATTERN.split(transtionProperty);
-        for(String property : propertiesArray){
-            String trim = property.trim();
-            if(TextUtils.isEmpty(trim)){
-                continue;
-            }
-            if(!(LAYOUT_PROPERTIES.contains(trim) || TRANSFORM_PROPERTIES.contains(trim))){
-                if(WXEnvironment.isApkDebugable()){
-                    WXLogUtils.e("WXTransition Property Not Supported" + trim + " in " + transtionProperty);
-                }
-                continue;
-            }
-            transition.properties.add(trim);
-        }
-    }
-
-    public List<String> getProperties() {
-        return properties;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/ArrayStack.java b/android/sdk/src/main/java/com/taobao/weex/el/parse/ArrayStack.java
deleted file mode 100644
index 0feb85e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/ArrayStack.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.el.parse;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * stack for parse and execute code
- * Created by jianbai.gbj on 2017/9/1.
- */
-public class ArrayStack<T> {
-
-    private ArrayList<T> stack;
-
-    public ArrayStack() {
-        this.stack = new ArrayList<T>(4);
-    }
-
-    public int size() {
-        return stack.size();
-    }
-
-    public T pop() {
-        return stack.remove(stack.size()-1);
-    }
-
-    public void push(T token) {
-        stack.add(token);
-    }
-
-
-    public T peek() {
-        return stack.get(stack.size()-1);
-    }
-
-    public T get(int i) {
-        return stack.get(i);
-    }
-
-    public T remove(int i) {
-        return stack.remove(i);
-    }
-
-    public void add(int i, T t) {
-        stack.add(i, t);
-    }
-
-    public boolean isEmpty() {
-        return   stack.isEmpty();
-    }
-
-    public List<T> getList(){
-        return stack;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java b/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java
deleted file mode 100644
index 6c3e29a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.el.parse;
-
-import com.alibaba.fastjson.JSONArray;
-
-import java.util.List;
-
-/**
- * block, has more than one tokens, but only first will be execute.
- * Created by jianbai.gbj on 2017/8/28.
- */
-class Block extends Token {
-    private List<Token> tokens;
-    public Block(List<Token> tokens,  int type) {
-        super("", type);
-        this.tokens = tokens;
-    }
-
-    @Override
-    public Object execute(Object context){
-        if(getType() == TYPE_ARRAY){
-            if(tokens == null || tokens.size() == 0){
-                return  new JSONArray(4);
-            }
-            JSONArray arrayList = new JSONArray(tokens.size());
-            for(int i=0; i<tokens.size(); i++){
-                Token token = tokens.get(i);
-                if(token == null){
-                    arrayList.add(null);
-                }else{
-                    arrayList.add(token.execute(context));
-                }
-            }
-            return arrayList;
-        }
-        if(tokens == null || tokens.size() == 0){
-            return  null;
-        }
-        Token token = tokens.get(0);
-        return token.execute(context);
-    }
-
-    @Override
-    public String toString() {
-        if(getType() == TYPE_ARRAY){
-            return "" + tokens + "";
-        }else {
-            if(tokens != null && tokens.size() == 1){
-                return "{" + tokens.get(0) + '}';
-            }
-            return "{" + tokens + '}';
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java b/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java
deleted file mode 100644
index d597be8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.el.parse;
-
-
-/**
- * Created by jianbai.gbj on 2017/8/28.
- * one operator, two operator, and three operator
- */
-class Operator extends Token {
-    public Token self;
-    public Token first;
-    public Token second;
-
-    public Operator(String operator, int type) {
-        super(operator, type);
-    }
-
-
-    @Override
-    public Object execute(Object context){
-        String op = getToken();
-        switch (op){
-            case  Operators.DOT_STR:
-            case  Operators.ARRAY_START_STR:{
-                return  Operators.dot(first, second, context);
-            }
-            case  Operators.EQUAL:
-            case  Operators.EQUAL2:{
-                return Operators.isEquals(first, second, context);
-            }
-            case  Operators.NOT_EQUAL:
-            case  Operators.NOT_EQUAL2:{
-                return !Operators.isEquals(first, second, context);
-            }
-            case  Operators.CONDITION_IF_STRING:{
-                return Operators.condition(self, first, second, context);
-            }
-            case  Operators.AND_NOT:{
-                return  !Operators.tokenTrue(self, context);
-            }
-            case  Operators.AND:{
-                return  Operators.tokenTrue(first, context) && Operators.tokenTrue(second, context);
-            }
-            case  Operators.OR:{
-                return  Operators.tokenTrue(first, context) || Operators.tokenTrue(second, context);
-            }
-            case  Operators.G:{
-                return  Operators.tokenNumber(first, context) > Operators.tokenNumber(second, context);
-            }
-            case  Operators.GE:{
-                return  Operators.tokenNumber(first, context) >= Operators.tokenNumber(second, context);
-            }
-            case  Operators.L:{
-                return  Operators.tokenNumber(first, context) < Operators.tokenNumber(second, context);
-            }
-            case  Operators.LE:{
-                return  Operators.tokenNumber(first, context) <= Operators.tokenNumber(second, context);
-            }
-            case  Operators.PLUS:{
-                return  Operators.plus(first, second, context);
-            }
-            case  Operators.SUB:{
-                return  Operators.sub(first, second, context);
-            }
-            case  Operators.MUL:{
-                return  Operators.mul(first, second, context);
-            }
-            case  Operators.DIV:{
-                return  Operators.div(first, second, context);
-            }
-            case  Operators.MOD:{
-                return  Operators.mod(first, second, context);
-            }
-            default:
-                throw new IllegalArgumentException(op + " operator is not supported");
-        }
-    }
-
-    @Override
-    public String toString() {
-        if(Operators.AND_NOT.equals(getToken())){
-            return "{!" +  self + "}";
-        }
-        if(self == null){
-            return "{" + first +  getToken() + second + "}";
-        }
-        return "{" + self + getToken() + first + ":" + second + "}";
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java b/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java
deleted file mode 100644
index d0bcb7e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java
+++ /dev/null
@@ -1,502 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.el.parse;
-
-import java.lang.reflect.Array;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-
-/**
- * Created by furture on 2017/8/28.
- */
-public class Operators {
-
-
-    public static Object dot(Token left, Token right, Object context){
-        if(left == null || right == null){
-            return null;
-        }
-        Object leftValue = left.execute(context);
-        if(leftValue == null){
-            return null;
-        }
-        Object value =  null;
-        if(right.getType() != Token.TYPE_IDENTIFIER){
-            Object identifter = right.execute(context);
-            if(identifter instanceof Double){
-                identifter = ((Double) identifter).intValue();
-            }
-            String key = identifter == null ? "" : identifter.toString().trim();
-            value = Operators.el(leftValue, key);
-        }else{
-            value = right.execute(leftValue);
-        }
-        if(value != null){
-            return value;
-        }
-        return  specialKey(leftValue, right.getToken());
-    }
-
-    /**
-     * get key's value on object
-     * */
-    public static  Object el(Object context, String key){
-        if(context == null){
-            return  null;
-        }
-        // TODO
-//        if(context instanceof CellRenderContext){
-//            if(WXEnvironment.isApkDebugable()){
-//                throw new IllegalArgumentException("rong context CellRenderContext, you should pass it's stack");
-//            }
-//            context = ((CellRenderContext) context).stack;
-//        }
-        if(context instanceof ArrayStack){
-            ArrayStack stack = (ArrayStack) context;
-            for(int index=stack.size()-1; index >= 0; index--){
-                Object value = stack.get(index);
-                if(value instanceof  Map){
-                    Map map = (Map) value;
-                    if(map.containsKey(key)){
-                        return map.get(key);
-                    }
-                }
-            }
-        }
-        if(context instanceof Stack){
-            Stack stack = (Stack) context;
-            for(int index=stack.size()-1; index >= 0; index--){
-                Object value = stack.get(index);
-                if(value instanceof  Map){
-                    Map map = (Map) value;
-                    if(map.containsKey(key)){
-                        return map.get(key);
-                    }
-                }
-            }
-        }
-
-        if(context instanceof  Map){
-            return ((Map) context).get(key);
-        }
-
-        if(context instanceof List){
-            List list = (List) context;
-            try{
-                return list.get(Integer.parseInt(key));
-            }catch (Exception e){}
-        }
-        if(context.getClass().isArray()){
-            try{
-                return Array.get(context, Integer.parseInt(key));
-            }catch (Exception e){}
-        }
-        return  null;
-    }
-
-    public static  Object specialKey(Object leftValue, String key){
-        if("length".equals(key)){
-            if(leftValue instanceof  CharSequence){
-                return ((CharSequence) leftValue).length();
-            }
-            if(leftValue instanceof  Map){
-                return  ((Map) leftValue).size();
-            }
-            if(leftValue instanceof  Map){
-                return  ((Map) leftValue).size();
-            }
-            if(leftValue instanceof  List){
-                return  ((List) leftValue).size();
-            }
-            if(leftValue.getClass().isArray()){
-                return Array.getLength(leftValue);
-            }
-        }
-        return null;
-    }
-
-    public static Object plus(Token left, Token right, Object context){
-        Object leftValue = null;
-        Object rightValue = null;
-        if(left != null){
-            leftValue = left.execute(context);
-        }
-        if(right  != null){
-            rightValue = right.execute(context);
-        }
-        if(leftValue instanceof  CharSequence || rightValue instanceof  CharSequence){
-            if(leftValue == null){
-                return  rightValue;
-            }
-            return leftValue.toString() + (rightValue == null ? "" : rightValue.toString());
-        }
-        if(leftValue instanceof  Number || rightValue instanceof Number){
-            return getNumber(leftValue) + getNumber(rightValue);
-        }
-        if(leftValue == null && rightValue == null){
-            return  null;
-        }
-        if(leftValue == null){
-            return  rightValue.toString();
-        }
-        return leftValue.toString() + (rightValue == null ? "" : rightValue.toString());
-    }
-
-
-    public static Object sub(Token left, Token right, Object context){
-        Object leftValue = null;
-        Object rightValue = null;
-        if(left != null){
-            leftValue = left.execute(context);
-        }
-        if(right  != null){
-            rightValue = right.execute(context);
-        }
-        return getNumber(leftValue) - getNumber(rightValue);
-    }
-
-    public static Object div(Token left, Token right, Object context){
-        Object leftValue = null;
-        Object rightValue = null;
-        if(left != null){
-            leftValue = left.execute(context);
-        }
-        if(right  != null){
-            rightValue = right.execute(context);
-        }
-        return getNumber(leftValue)/getNumber(rightValue);
-    }
-
-    public static Object mul(Token left, Token right, Object context){
-        Object leftValue = null;
-        Object rightValue = null;
-        if(left != null){
-            leftValue = left.execute(context);
-        }
-        if(right  != null){
-            rightValue = right.execute(context);
-        }
-        return getNumber(leftValue)*getNumber(rightValue);
-    }
-
-    public static Object mod(Token left, Token right, Object context){
-        Object leftValue = null;
-        Object rightValue = null;
-        if(left != null){
-            leftValue = left.execute(context);
-        }
-        if(right  != null){
-            rightValue = right.execute(context);
-        }
-        return (getNumber(leftValue))%(getNumber(rightValue));
-    }
-
-    /**
-     * condition expression
-     * */
-    public static Object condition(Token selfs, Token first, Token second, Object context){
-        boolean value = false;
-        if(selfs != null){
-            value = isTrue(selfs.execute(context));
-        }
-        if(value){
-            if(first != null){
-                return  first.execute(context);
-            }
-        }else{
-            if(second != null){
-                return  second.execute(context);
-            }
-        }
-        return null;
-    }
-
-
-    /**
-     * is token value is true
-     * */
-    public static boolean tokenTrue(Token selfs, Object context) {
-        if(selfs == null){
-            return false;
-        }
-        Object value = selfs.execute(context);
-        return  isTrue(value);
-    }
-
-    /**
-     * get token number
-     * */
-    public static double tokenNumber(Token self,  Object context) {
-        if(self == null){
-            return  0;
-        }
-        Object value = self.execute(context);
-        return  getNumber(value);
-    }
-
-
-
-    /**
-     * isEquls operation
-     * */
-    public static boolean isEquals(Token left, Token right, Object context){
-        if(left == null && right == null){
-            return  true;
-        }
-        Object leftValue =  null;
-        if(left != null){
-            leftValue  = left.execute(context);
-        }
-        Object rightValue = null;
-        if(right != null) {
-            rightValue = right.execute(context);
-        }
-        if(leftValue == null){
-            if(rightValue == null){
-                return  true;
-            }
-            if(rightValue instanceof  CharSequence){
-                if(isEmpty(rightValue.toString())){
-                    return  true;
-                }
-            }
-            return  false;
-        }
-        if(rightValue == null){
-            if(isEmpty(leftValue.toString())){
-                return  true;
-            }
-            return  false;
-        }
-        if(leftValue instanceof  Number){
-            if(rightValue instanceof  Number){
-                return  ((Number) leftValue).doubleValue() == ((Number) rightValue).doubleValue();
-            }
-            return ((Number) leftValue).doubleValue() == getNumber(rightValue);
-        }
-        if(rightValue instanceof  Number){
-            return getNumber(leftValue) == ((Number) rightValue).doubleValue();
-        }
-        if(leftValue instanceof CharSequence
-                ||  rightValue instanceof CharSequence){
-            return  leftValue.toString().trim().equals(rightValue.toString().trim());
-        }
-        return  leftValue.equals(rightValue);
-    }
-
-
-    /**
-     * check whether value is true
-     * */
-    public static boolean isTrue(Object value){
-        if(value == null){
-            return  false;
-        }
-        if(value instanceof  Number){
-            return ((Number) value).doubleValue() != 0;
-        }
-        String bool = value.toString().trim();
-        if("false".equals(bool)
-                || "undefined".equals(bool)
-                || "null".equals(bool)){
-            return  false;
-        }
-        if(isEmpty(bool)){
-            return  false;
-        }
-        return  true;
-    }
-
-    /**
-     * check String value is empty
-     * */
-    public static boolean isEmpty(String value){
-        if (value == null){
-            return  true;
-        }
-        for(int i=0; i<value.length(); i++){
-            if(value.charAt(i) != ' '){
-                return  false;
-            }
-        }
-        return true;
-    }
-
-
-    /**
-     * get number
-     * */
-    public static double getNumber(Object value){
-        if(value == null){
-            return  0;
-        }
-        if(value instanceof  Number){
-            return  ((Number) value).doubleValue();
-        }
-        try{
-            return Double.parseDouble(value.toString());
-        }catch (Exception e){return  0;}
-    }
-
-    public static boolean isOpEnd(String op){
-        return isOpEnd(op.charAt(0));
-    }
-    /**
-     * op end, has none operation, should not enter operator stack.
-     * */
-    public static boolean isOpEnd(char op){
-        if(op == BRACKET_END
-                || op == ARRAY_END
-                || op == SPACE
-                || op == ARRAY_SEPRATOR){
-            return true;
-        }
-        return  false;
-    }
-
-    /**
-     * is not
-     * */
-    public static boolean isDot(String opStr){
-        char op = opStr.charAt(0);
-        return  op == DOT || op == ARRAY_START;
-    }
-
-
-
-
-    public static final char BRACKET_END = ')';
-    public static final String BRACKET_END_STR = ")";
-    public static final char BRACKET_START = '(';
-    public static final String BRACKET_START_STR = "(";
-    public static final char QUOTE = '"';
-    public static final char SINGLE_QUOTE = '\'';
-    public static final char DOT = '.';
-    public static final String DOT_STR = ".";
-    public static final char ARRAY_START = '[';
-    public static final String ARRAY_START_STR = "[";
-    public static final char ARRAY_SEPRATOR = ',';
-    public static final String ARRAY_SEPRATOR_STR = ",";
-    public static final char ARRAY_END = ']';
-    public static final String ARRAY_END_STR = "]";
-    public static final String SPACE_STR = " ";
-    public static final char SPACE = ' ';
-    public static final char BLOCK_START = '{';
-    public static final String BLOCK_START_STR = "{";
-    public static final char BLOCK_END = '}';
-    public static final String BLOCK_END_STR = "}";
-    public static final char DOLLAR = '$';
-    public static final String DOLLAR_STR = "$";
-
-    /**
-     * condition
-     * */
-    public static final char  CONDITION_IF = '?';
-    public static final String  CONDITION_IF_STRING = "?";
-    public static final char  CONDITION_IF_MIDDLE = ':';
-
-
-
-    /**
-     * match
-     * */
-    public static final String PLUS ="+";
-    public static final String SUB = "-";
-    public static final String MUL = "*";
-    public static final String DIV = "/";
-    public static final String MOD = "%";
-
-
-
-    public static final String AND  = "&&";
-    public static final String OR  = "||";
-    /**
-     * and operator
-     * */
-    public static final String EQUAL = "===";
-    public static final String EQUAL2 = "==";
-    public static final String NOT_EQUAL = "!==";
-    public static final String NOT_EQUAL2 = "!=";
-    public static final String AND_NOT = "!";
-
-
-    public static final String G = ">";
-    public static final String GE = ">=";
-    public static final String LE = "<=";
-    public static final String L = "<";
-
-
-
-
-
-    /**
-     * https://github.com/jquery/esprima/blob/master/src/parser.ts
-     * */
-    public static Map<String, Integer> OPERATORS_PRIORITY = new HashMap<>();
-    static {
-        OPERATORS_PRIORITY.put(BLOCK_END_STR, 0);
-        OPERATORS_PRIORITY.put(BRACKET_END_STR, 0);
-        OPERATORS_PRIORITY.put(SPACE_STR, 0);
-        OPERATORS_PRIORITY.put(ARRAY_SEPRATOR_STR, 0);
-        OPERATORS_PRIORITY.put(ARRAY_END_STR, 0);
-
-
-        OPERATORS_PRIORITY.put(OR, 1);
-        OPERATORS_PRIORITY.put(AND, 1);
-
-        OPERATORS_PRIORITY.put(EQUAL, 2);
-        OPERATORS_PRIORITY.put(EQUAL2, 2);
-        OPERATORS_PRIORITY.put(NOT_EQUAL, 2);
-        OPERATORS_PRIORITY.put(NOT_EQUAL2, 2);
-
-        OPERATORS_PRIORITY.put(G, 7);
-        OPERATORS_PRIORITY.put(GE, 7);
-        OPERATORS_PRIORITY.put(L, 7);
-        OPERATORS_PRIORITY.put(LE, 8);
-
-        OPERATORS_PRIORITY.put(PLUS, 9);
-        OPERATORS_PRIORITY.put(SUB, 9);
-        OPERATORS_PRIORITY.put(MUL, 10);
-        OPERATORS_PRIORITY.put(DIV, 10);
-        OPERATORS_PRIORITY.put(MOD, 10);
-        OPERATORS_PRIORITY.put(AND_NOT, 11);
-
-        OPERATORS_PRIORITY.put(DOT_STR, 15);
-        
-        OPERATORS_PRIORITY.put(ARRAY_START_STR, 16);
-
-
-        OPERATORS_PRIORITY.put(BRACKET_START_STR, 17);
-        OPERATORS_PRIORITY.put(BLOCK_START_STR, 17);
-
-
-    }
-
-
-    public static final Map<String,Object> KEYWORDS = new HashMap<>();
-    static {
-        KEYWORDS.put("null", null);
-        KEYWORDS.put("true", Boolean.TRUE);
-        KEYWORDS.put("false", Boolean.FALSE);
-        KEYWORDS.put("undefined", null);
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Parser.java b/android/sdk/src/main/java/com/taobao/weex/el/parse/Parser.java
deleted file mode 100644
index 6609e3f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Parser.java
+++ /dev/null
@@ -1,486 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.el.parse;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * Created by furture on 2017/8/28.
- * simple expression parse, less ast node and save memory
- */
-public class Parser {
-
-    private String code;
-    private int position;
-    private ArrayStack<Token> stacks;
-    private ArrayStack<Symbol> operators;
-
-    public Parser(String code){
-        this.code = code;
-        this.position = 0;
-        this.stacks = new ArrayStack<>();
-        this.operators = new ArrayStack<>();
-    }
-
-
-    public final Token parse(){
-        while (hasNextToken()){
-            scanNextToken();
-        }
-        while (!operators.isEmpty()){
-            Symbol op = operators.pop();
-            doOperator(op);
-        }
-        if(stacks.size() == 1){
-            return  stacks.pop();
-        }
-        Block block = new Block(stacks.getList(), Token.TYPE_BLOCK);
-        return block;
-    }
-
-
-    /**
-     * parse code to ast block.
-     * */
-    public static Token parse(String code){
-        try{
-            Parser parser = new Parser(code);
-            return parser.parse();
-        }catch (Exception e){
-            if(WXEnvironment.isApkDebugable()){
-                WXLogUtils.e("code " + code, e);
-            }
-            return new Block(null, Token.TYPE_BLOCK);
-        }
-    }
-
-
-    final char scanNextToken(){
-        char ch = nextToken();
-        if(ch == Operators.DOLLAR){
-            position++;
-            return ch;
-        }else if(Character.isJavaIdentifierStart(ch)){
-            scanIdentifier();
-        }else if (ch == Operators.BRACKET_START || ch == Operators.BLOCK_START) {
-            scanBracket();
-        }else if (ch == Operators.ARRAY_START) {
-            scanArray();
-        }else if (ch ==  Operators.QUOTE || ch == Operators.SINGLE_QUOTE) {
-            scanString();
-        }else if((ch == Operators.DOT && Character.isDigit(code.charAt(position + 1)))
-                || Character.isDigit(ch)){ //number .00 .00e6
-            scanNumber();
-        }else if(ch ==  Operators.CONDITION_IF){
-            scanIf();
-        }else if(ch ==  Operators.CONDITION_IF_MIDDLE
-                || ch ==  Operators.BRACKET_END
-                || ch == Operators.BLOCK_END
-                || ch == Operators.SPACE
-                || ch == Operators.ARRAY_END){
-            position++;
-            return ch;
-        }else{
-            scanOperator();
-        }
-        return ch;
-    }
-
-
-    final void  scanArray(){
-        int stackSize = stacks.size();
-        int opSize = operators.size();
-        int type = Token.TYPE_IDENTIFIER;
-        if(position - 1 < 0 || !Character.isJavaIdentifierPart(code.charAt(position - 1))){
-            type = Token.TYPE_ARRAY;
-        }
-        operators.push(new Symbol(Operators.ARRAY_START_STR, stacks.size()));
-        position++;
-        while (hasNextToken()){
-            char token = scanNextToken();
-            if(token == Operators.ARRAY_END){
-                break;
-            }
-        }
-
-        if(stacks.size() <= stackSize){ // empty bracket, none need, save memory
-            while (operators.size() > opSize){
-                operators.pop();
-            }
-            return;
-        }
-
-        while (operators.size() > opSize){
-            Symbol op = operators.pop();
-            if(stacks.size() > stackSize){
-                doOperator(op);
-            }
-        }
-        List<Token> tokens = new ArrayList<>(4);
-        for(int i=stackSize; i<stacks.size(); i++){
-            tokens.add(stacks.get(i));
-        }
-        while (stacks.size() > stackSize){
-            stacks.pop();
-        }
-        if(type == Token.TYPE_ARRAY || stacks.size() == 0){
-            Block block = new Block(tokens, Token.TYPE_ARRAY);
-            stacks.push(block);
-            return;
-        }
-
-        Token identifer = stacks.pop();
-        Token second = null;
-        if(tokens.size() == 1){
-            second = tokens.get(0);
-        }else{
-            second = new Block(tokens, Token.TYPE_BLOCK);
-        }
-        Operator operator = new Operator(Operators.DOT_STR, type);
-        operator.first = identifer;
-        operator.second = second;
-        stacks.push(operator);
-    }
-
-    void  scanBracket(){
-        int stackSize = stacks.size();
-        int opSize = operators.size();
-        if(code.charAt(position) == Operators.BLOCK_START){
-            operators.push(new Symbol(Operators.BLOCK_START_STR, stacks.size()));
-            position++;
-            while (hasNextToken()){
-                if(scanNextToken() == Operators.BLOCK_END){
-                    break;
-                }
-            }
-        }else{
-            operators.push(new Symbol(Operators.BRACKET_START_STR, stacks.size()));
-            position++;
-            while (hasNextToken()){
-                if(scanNextToken() == Operators.BRACKET_END){
-                    break;
-                }
-            }
-        }
-        if(stacks.size() <= stackSize){ // empty bracket, none need, save memory
-            while (operators.size() > opSize){
-                operators.pop();
-            }
-            return;
-        }
-        while (operators.size() > opSize){
-            Symbol op = operators.pop();
-            if(stacks.size() > stackSize){
-                doOperator(op);
-            }
-        }
-        List<Token> tokens = new ArrayList<>(4);
-        for(int i=stackSize; i<stacks.size(); i++){
-            tokens.add(stacks.get(i));
-        }
-        while (stacks.size() > stackSize){
-            stacks.pop();
-        }
-        if(tokens.size() == 1){
-            stacks.push(tokens.get(0));
-        }else{
-            Block block = new Block(tokens, Token.TYPE_BLOCK);
-            stacks.push(block);
-        }
-    }
-
-    /**
-     * 1  === (1 + 3) &&  1
-     * scan operator
-     * */
-    void scanOperator(){
-        int start = position;
-        int length = Math.min(position + 3, code.length());
-        String operator = code.substring(position, length);
-        if(operator.length() >= 3){
-            if(!Operators.OPERATORS_PRIORITY.containsKey(operator)){
-                operator = operator.substring(0, 2);
-            }
-        }
-        if(operator.length() >= 2){
-            if(!Operators.OPERATORS_PRIORITY.containsKey(operator)){
-                operator = operator.substring(0, 1);
-            }
-        }
-        if(!Operators.OPERATORS_PRIORITY.containsKey(operator)){
-            //just skip illegal character
-            int illegalChar = Math.min(start + 1, code.length());
-            WXLogUtils.e("weex", new IllegalArgumentException(code.substring(0, illegalChar) + " illegal code operator" + operator));
-            position += operator.length();
-            return;
-        }
-        if((!operators.isEmpty() && operators.peek() != null)){
-            String preOp = operators.peek().op;
-            if(Operators.OPERATORS_PRIORITY.get(preOp) >= Operators.OPERATORS_PRIORITY.get(operator)){
-                Symbol op = operators.pop();
-                doOperator(op);
-            }
-        }
-        if(!Operators.isOpEnd(operator)){
-            operators.push(new Symbol(operator, stacks.size()));
-        }
-        position += operator.length();
-    }
-
-
-
-    void doOperator(Symbol symbol){
-        String op = symbol.op;
-        if(Operators.BRACKET_START_STR.equals(symbol.op)
-                || Operators.BLOCK_START_STR.equals(symbol.op)
-                || Operators.ARRAY_START_STR.equals(symbol.op)
-                || Operators.DOLLAR_STR.equals(symbol.op)){
-            return;
-        }
-        if(Operators.BLOCK_START_STR.equals(symbol.op)){
-            return;
-        }
-        int second = symbol.pos;
-        int first  = Math.max(symbol.pos - 1, 0);
-        if(!operators.isEmpty()){
-            first = Math.max(first, operators.peek().pos);
-        }
-
-        Operator operator = new Operator(op, Token.TYPE_OPERATOR);
-        if(Operators.AND_NOT.equals(op)){
-            if(stacks.size() > second) {
-                Token token = stacks.remove(second);
-                operator.self = token;
-                stacks.add(second, operator);
-                return;
-            }
-            return; //invalid
-        }
-        if(stacks.size() > second) {
-            operator.second = stacks.remove(second);
-        }else{
-            return;
-        }
-        if(stacks.size() > first) {
-            operator.first = stacks.remove(first);
-        }else{
-            if(operator.second == null){
-                return;
-            }
-        }
-        stacks.add(first, operator);
-    }
-
-    /**
-     * condition if
-     * */
-    void scanIf(){
-        Operator operator = new Operator(Operators.CONDITION_IF_STRING, Token.TYPE_OPERATOR);
-        int selfIndex = 0;
-        doStackOperators(0);
-        if(operators.size() > 0){
-            selfIndex = Math.max(operators.peek().pos, selfIndex);
-        }
-        if(stacks.size() > selfIndex){
-            operator.self = stacks.pop();
-        }
-
-        int stackSize = stacks.size();
-        int leftOperatorSize = operators.size();
-        position++;
-        while (hasNextToken()){
-            if(scanNextToken() == Operators.CONDITION_IF_MIDDLE){
-                break;
-            }
-        }
-        while (operators.size() > leftOperatorSize){
-            Symbol symbol = operators.pop();
-            doOperator(symbol);
-        }
-
-        while (stacks.size() > stackSize){
-            operator.first = stacks.pop();
-        }
-        int rightOperatorsSize = operators.size();
-        while (hasNextToken()){
-            scanNextToken();
-            if(hasNextToken()){
-                scanNextToken();
-            }
-            if(operators.size() <= rightOperatorsSize){
-                break;
-            }
-        }
-        doStackOperators(rightOperatorsSize);
-        while (stacks.size() > stackSize){
-            operator.second = stacks.pop();
-        }
-        stacks.push(operator);
-    }
-
-    private final void doStackOperators(int operatorSize){
-        while (operators.size() > operatorSize){
-            Symbol symbol = operators.pop();
-            doOperator(symbol);
-        }
-    }
-
-    /**
-     * 1+e6
-     * .00
-     * .00e6
-     * 100
-     * 199e5
-     * */
-    final void scanNumber(){
-        boolean isInt = true;
-        int start = position;
-        if(code.charAt(position) == 'e' || code.charAt(position) == '.'){
-            isInt = false;
-        }
-        position++;
-        while (hasNext()){
-            char ch = code.charAt(position);
-            if(Character.isDigit(ch)
-                    || ch == '.'
-                    || ch =='e'){
-                if(ch == 'e'
-                        || ch == '.'){
-                    isInt = false;
-                }
-                position++;
-            }else{
-                break;
-            }
-        }
-        String number = code.substring(start, position);
-        if(".".equals(number)){
-            return;
-        }
-        Token stack = null;
-        if(isInt){
-            stack = new Token(number, Token.TYPE_INT);
-        }else{
-            stack = new Token(number, Token.TYPE_DOUBLE);
-        }
-        stacks.push(stack);
-    }
-
-
-    final void  scanString(){
-        int start = position;
-        ArrayStack operator = new ArrayStack();
-        char quote = code.charAt(start);
-        operator.push(quote);
-        StringBuilder builder = new StringBuilder();
-        for(position= start + 1; position<code.length(); position++){
-            char ch = code.charAt(position);
-            if(ch == quote){
-                if(code.charAt(position -1) != '\\'){
-                    operator.pop();
-                    if(operator.size() == 0){
-                       position++;
-                       break;
-                    }
-                }else{
-                    builder.deleteCharAt(builder.length()-1);
-                    builder.append(ch);
-                }
-            }else{
-                builder.append(ch);
-            }
-        }
-        String string =  builder.toString();
-        Token token = new Token(string, Token.TYPE_STRING);
-        stacks.push(token);
-    }
-
-
-
-    /**
-     * scan el expression.
-     * item.ddd
-     * ${item.dd}
-     * $item.dd
-     * */
-    final void scanIdentifier(){
-        int start = position;
-        position++;
-        while (hasNext()){
-            char ch = code.charAt(position);
-            if(Character.isJavaIdentifierPart(ch)){
-               position++;
-            }else{
-                break;
-            }
-            //2.true
-        }
-        String el = code.substring(start, position);
-        if(el.startsWith(Operators.DOLLAR_STR)){
-            if(el.length() == Operators.DOLLAR_STR.length()){
-                return;
-            }
-            el = el.substring(Operators.DOLLAR_STR.length());
-        }
-        int type = Token.TYPE_IDENTIFIER;
-        if(Operators.KEYWORDS.containsKey(el)){
-            if(!(!operators.isEmpty() && Operators.isDot(operators.peek().op))){
-                type = Token.TYPE_KEYWORD;
-            }
-        }
-        Token token = new Token(el, type);
-        stacks.push(token);
-    }
-
-
-    final boolean hasNext(){
-        return position < code.length();
-    }
-
-
-
-    final boolean hasNextToken(){
-        while (hasNext()){
-            char ch = code.charAt(position);
-            if(ch == ' '){
-                position++;
-                continue;
-            }
-            return  true;
-        }
-        return false;
-    }
-
-    final char nextToken(){
-        char ch = code.charAt(position);
-        while (ch == ' '){
-            position ++;
-            if(code.length() <= position){
-                break;
-            }
-            ch = code.charAt(position);
-        }
-        return ch;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Symbol.java b/android/sdk/src/main/java/com/taobao/weex/el/parse/Symbol.java
deleted file mode 100644
index e42aa78..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Symbol.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.el.parse;
-
-/**
- * Created by furture on 2017/8/29.
- */
-
-public class Symbol {
-    public final String op;
-    public final int pos;
-    public Symbol(String op, int pos) {
-        this.op = op;
-        this.pos = pos;
-    }
-
-    /**
-    @Override
-    public String toString() {
-        return op;
-    }*/
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java b/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java
deleted file mode 100644
index 44f9135..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.el.parse;
-
-/**
- * Created by furture on 2017/8/28.
- */
-public class Token {
-
-    /**
-     * token's type
-     * */
-    public static final int TYPE_IDENTIFIER = 0;
-    public static final int TYPE_INT = 1;
-    public static final int TYPE_DOUBLE = 2;
-    public static final int TYPE_STRING = 3;
-    public static final int TYPE_KEYWORD = 4;
-    public static final int TYPE_OPERATOR = 5;
-    public static final int TYPE_BLOCK = 6;
-
-    public static final int TYPE_ARRAY = 7;
-
-
-
-    private String token;
-    private int type;
-
-    public Token(String token, int type){
-        this.token = token;
-        this.type = type;
-    }
-
-
-    /**
-     * stack should use array stack.
-     * execute token in context, and return value.
-     * */
-    public Object execute(Object context){
-        if(type == TYPE_IDENTIFIER){
-            return Operators.el(context, token);
-        }else if(type == TYPE_STRING){
-            return  token;
-        }else if(type == TYPE_INT){
-            try{
-                return  Integer.parseInt(token);
-            }catch (Exception e){
-                return 0;
-            }
-        }else if(type == TYPE_DOUBLE){
-            try{
-                return  Double.parseDouble(token);
-            }catch (Exception e){
-                return 0;
-            }
-        }else if(type == TYPE_KEYWORD){
-            return  Operators.KEYWORDS.get(token);
-        }
-        throw new IllegalArgumentException("unhandled token type " + type);
-    }
-
-    @Override
-    public String toString() {
-        return "{" + token + "," + type + '}';
-    }
-
-    public String getToken() {
-        return token;
-    }
-
-    public int getType() {
-        return type;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/font/FontAdapter.java b/android/sdk/src/main/java/com/taobao/weex/font/FontAdapter.java
deleted file mode 100644
index 4556a39..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/font/FontAdapter.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.font;
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public class FontAdapter {
-
-
-    private List<FontListener> mFontListener;
-
-    public FontAdapter(){
-        mFontListener = new CopyOnWriteArrayList<>();
-    }
-
-    public void addFontListener(FontListener fontListener){
-        mFontListener.add(fontListener);
-    }
-
-    public void removeFontListener(FontListener fontListener){
-        mFontListener.remove(fontListener);
-    }
-
-    public void onAddFontRule(String pageId, String fontFamily, String fontUrl){
-        synchronized (this){
-            for(FontListener fontListener : mFontListener){
-                fontListener.onAddFontRule(pageId, fontFamily, fontUrl);
-            }
-        }
-    }
-
-    public void onFontLoad(String fontFaimly, String fontUrl, String filePath){
-        synchronized (this) {
-            for (FontListener fontListener : mFontListener) {
-                fontListener.onFontLoad(fontFaimly, fontUrl, filePath);
-            }
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/font/FontListener.java b/android/sdk/src/main/java/com/taobao/weex/font/FontListener.java
deleted file mode 100644
index e6d70a5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/font/FontListener.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.font;
-
-public interface FontListener {
-
-    public void onAddFontRule(String pageId, String fontFamily, String fontUrl);
-
-    public void onFontLoad(String fontFamily, String fontUrl, String filePath);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/http/Options.java b/android/sdk/src/main/java/com/taobao/weex/http/Options.java
deleted file mode 100644
index effb241..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/http/Options.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.http;
-
-import java.util.HashMap;
-import java.util.Map;
-import com.taobao.weex.common.*;
-
-/**
- * Created by sospartan on 5/19/16.
- */
-class Options {
-  private String method;
-  private String url;
-  private Map<String, String> headers;
-  private String body;
-  private Type type = Type.text;
-  private int timeout = WXRequest.DEFAULT_TIMEOUT_MS;
-
-  private Options(String method,
-                  String url,
-                  Map<String, String> headers,
-                  String body,
-                  Type type,
-                  int timeout) {
-    this.method = method;
-    this.url = url;
-    this.headers = headers;
-    this.body = body;
-    this.type = type;
-    if (timeout == 0) {
-      timeout = WXRequest.DEFAULT_TIMEOUT_MS;
-    }
-    this.timeout = timeout;
-  }
-
-  public String getMethod() {
-    return method;
-  }
-
-  public String getUrl() {
-    return url;
-  }
-
-  public Map<String, String> getHeaders() {
-    return headers;
-  }
-
-  public String getBody() {
-    return body;
-  }
-
-  public Type getType() {
-    return type;
-  }
-
-  public int getTimeout() { return timeout; }
-
-  public enum Type {
-    json, text,jsonp
-  }
-
-  public static class Builder {
-    private String method;
-    private String url;
-    private Map<String, String> headers = new HashMap<>();
-    private String body;
-    private Type type;
-    private int timeout;
-
-    public Builder setMethod(String method) {
-      this.method = method;
-      return this;
-    }
-
-    public Builder setUrl(String url) {
-      this.url = url;
-      return this;
-    }
-
-    public Builder putHeader(String key,String value){
-      this.headers.put(key,value);
-      return this;
-    }
-
-    public Builder setBody(String body) {
-      this.body = body;
-      return this;
-    }
-
-    /**
-     * default text
-     * json = jsonp
-     * @param type
-     * @return
-       */
-    public Builder setType(String type) {
-      if(Type.json.name().equals(type)){
-        this.type = Type.json;
-      }else if(Type.jsonp.name().equals(type)){
-        this.type = Type.jsonp;
-      }else{
-        this.type = Type.text;
-      }
-      return this;
-    }
-
-    public Builder setType(Type type) {
-      this.type = type;
-      return this;
-    }
-
-    public Builder setTimeout(int timeout) {
-      this.timeout = timeout;
-      return this;
-    }
-
-    public Options createOptions() {
-      return new Options(method, url, headers, body, type, timeout);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/http/Status.java b/android/sdk/src/main/java/com/taobao/weex/http/Status.java
deleted file mode 100644
index 429f53f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/http/Status.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.http;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by sospartan on 5/26/16.
- */
-public class Status {
-  public static final String UNKNOWN_STATUS = "unknown status";
-  public static final String ERR_INVALID_REQUEST = "ERR_INVALID_REQUEST";
-  public static final String ERR_CONNECT_FAILED = "ERR_CONNECT_FAILED";
-
-  private static Map<String,String> statusMap = new HashMap<>();
-
-  static {
-    statusMap.put("100","Continue");
-    statusMap.put("101","Switching Protocol");
-    statusMap.put("200","OK");
-    statusMap.put("201","Created");
-    statusMap.put("202","Accepted");
-    statusMap.put("203","Non-Authoritative Information");
-    statusMap.put("204","No Content");
-    statusMap.put("205","Reset Content");
-    statusMap.put("206","Partial Content");
-    statusMap.put("300","Multiple Choice");
-    statusMap.put("301","Moved Permanently");
-    statusMap.put("302","Found");
-    statusMap.put("303","See Other");
-    statusMap.put("304","Not Modified");
-    statusMap.put("305","Use Proxy");
-    statusMap.put("306","unused");
-    statusMap.put("307","Temporary Redirect");
-    statusMap.put("308","Permanent Redirect");
-    statusMap.put("400","Bad Request");
-    statusMap.put("401","Unauthorized");
-    statusMap.put("402","Payment Required");
-    statusMap.put("403","Forbidden");
-    statusMap.put("404","Not Found");
-    statusMap.put("405","Method Not Allowed");
-    statusMap.put("406","Not Acceptable");
-    statusMap.put("407","Proxy Authentication Required");
-    statusMap.put("408","Request Timeout");
-    statusMap.put("409","Conflict");
-    statusMap.put("410","Gone");
-    statusMap.put("411","Length Required");
-    statusMap.put("412","Precondition Failed");
-    statusMap.put("413","Payload Too Large");
-    statusMap.put("414","URI Too Long");
-    statusMap.put("415","Unsupported Media Type");
-    statusMap.put("416","Requested Range Not Satisfiable");
-    statusMap.put("417","Expectation Failed");
-    statusMap.put("418","I'm a teapot");
-    statusMap.put("421","Misdirected Request");
-    statusMap.put("426","Upgrade Required");
-    statusMap.put("428","Precondition Required");
-    statusMap.put("429","Too Many Requests");
-    statusMap.put("431","Request Header Fields Too Large");
-    statusMap.put("500","Internal Server Error");
-    statusMap.put("501","Not Implemented");
-    statusMap.put("502","Bad Gateway");
-    statusMap.put("503","Service Unavailable");
-    statusMap.put("504","Gateway Timeout");
-    statusMap.put("505","HTTP Version Not Supported");
-    statusMap.put("506","Variant Also Negotiates");
-    statusMap.put("507","Variant Also Negotiates");
-    statusMap.put("511","Network Authentication Required");
-  }
-
-  public static String getStatusText(String code){
-    if(!statusMap.containsKey(code))
-      return UNKNOWN_STATUS;
-    return statusMap.get(code);
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/http/WXHttpUtil.java b/android/sdk/src/main/java/com/taobao/weex/http/WXHttpUtil.java
deleted file mode 100644
index 4f58841..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/http/WXHttpUtil.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.http;
-
-import android.content.Context;
-import android.text.TextUtils;
-
-import com.taobao.weex.common.WXConfig;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.Map;
-
-/**
- * Created by lixinke on 16/4/6.
- */
-public class WXHttpUtil {
-
-  private static String sDefaultUA = null;
-
-  public static final String KEY_USER_AGENT = "user-agent";
-
-  public static String assembleUserAgent(Context ctx,Map<String, String> config) {
-    if (TextUtils.isEmpty(sDefaultUA)) {
-      StringBuilder builder = new StringBuilder();
-      builder.append(config.get(WXConfig.sysModel))
-          .append("(Android/")
-          .append(config.get(WXConfig.sysVersion))
-          .append(")")
-          .append(" ")
-
-          .append(TextUtils.isEmpty(config.get(WXConfig.appGroup)) ? "" : config.get(WXConfig.appGroup))
-          .append("(")
-          .append(TextUtils.isEmpty(config.get(WXConfig.appName)) ? "" : config.get(WXConfig.appName))
-          .append("/")
-          .append(config.get(WXConfig.appVersion))
-          .append(")")
-          .append(" ")
-
-          .append("Weex/")
-          .append(config.get(WXConfig.weexVersion))
-          .append(" ")
-
-          .append(TextUtils.isEmpty(config.get(WXConfig.externalUserAgent)) ? "" : config.get(WXConfig.externalUserAgent))
-          .append(TextUtils.isEmpty(config.get(WXConfig.externalUserAgent)) ? "" : " ")
-
-          .append(WXViewUtils.getScreenWidth(ctx) + "x" + WXViewUtils.getScreenHeight(ctx));
-      sDefaultUA = builder.toString();
-    }
-    return sDefaultUA;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/http/WXStreamModule.java b/android/sdk/src/main/java/com/taobao/weex/http/WXStreamModule.java
deleted file mode 100644
index 3e8e9e5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/http/WXStreamModule.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.http;
-
-import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT;
-
-import android.net.Uri;
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.common.WXResponse;
-import com.taobao.weex.performance.WXStateRecord;
-import com.taobao.weex.utils.WXLogUtils;
-import java.io.UnsupportedEncodingException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class WXStreamModule extends WXModule {
-
-  public static final String STATUS_TEXT = "statusText";
-  public static final String STATUS = "status";
-  final IWXHttpAdapter mAdapter;
-  static final Pattern CHARSET_PATTERN = Pattern.compile("charset=([a-z0-9-]+)");
-
-  public WXStreamModule(){
-    this(null);
-  }
-  public WXStreamModule(IWXHttpAdapter adapter){
-    mAdapter = adapter;
-  }
-
-  /**
-   * send HTTP request
-   *
-   * @param params   {method:POST/GET/PUT/DELETE/HEAD/PATCH,url:http://xxx,header:{key:value},
-   *                 body:{key:value}}
-   * @param callback formate:handler(err, response)
-   */
-  @Deprecated
-  @JSMethod(uiThread = false)
-  public void sendHttp(JSONObject paramsObj, final String callback) {
-
-    String method = paramsObj.getString("method");
-    String url = paramsObj.getString("url");
-    JSONObject headers = paramsObj.getJSONObject("header");
-    String body = paramsObj.getString("body");
-    int timeout = paramsObj.getIntValue("timeout");
-
-    if (method != null) method = method.toUpperCase(Locale.ROOT);
-    Options.Builder builder = new Options.Builder()
-            .setMethod(!"GET".equals(method)
-                    &&!"POST".equals(method)
-                    &&!"PUT".equals(method)
-                    &&!"DELETE".equals(method)
-                    &&!"HEAD".equals(method)
-                    &&!"PATCH".equals(method)?"GET":method)
-            .setUrl(url)
-            .setBody(body)
-            .setTimeout(timeout);
-
-    extractHeaders(headers,builder);
-    sendRequest(builder.createOptions(), new ResponseCallback() {
-      @Override
-      public void onResponse(WXResponse response, Map<String, String> headers) {
-        if(callback != null && mWXSDKInstance != null)
-          WXBridgeManager.getInstance().callback(mWXSDKInstance.getInstanceId(), callback,
-                  (response == null || response.originalData == null) ? "{}" :
-                          readAsString(response.originalData,
-                                  headers!=null?getHeader(headers,"Content-Type"):""
-                          ));
-      }
-    }, null, mWXSDKInstance.getInstanceId(), mWXSDKInstance.getBundleUrl());
-  }
-
-  /**
-   *
-   * @param optionsStr request options include:
-   *  method: GET 、POST、PUT、DELETE、HEAD、PATCH
-   *  headers:object,request header
-   *  url:
-   *  body: "Any body that you want to add to your request"
-   *  type: json、text、jsonp(json)
-   * @param callback finished callback,response object:
-   *  status:status code
-   *  ok:boolean is success,http status200~299
-   *  statusText: statusText
-   *  data:  option type is json,data is object,not data is string
-   *  headers: headers
-   *
-   * @param progressCallback in progress callback,for download progress and request state,response object:
-   *  readyState: number connection status 1 OPENED 2 HEADERS_RECEIVED 3 LOADING
-   *  status:status code
-   *  length:headers Content-Length
-   *  statusText:statusText
-   *  headers: headers
-   */
-  @JSMethod(uiThread = false)
-  public void fetch(JSONObject optionsObj , final JSCallback callback, JSCallback progressCallback){
-    fetch(optionsObj, callback, progressCallback, mWXSDKInstance.getInstanceId(), mWXSDKInstance.getBundleUrl());
-  }
-
-  public void fetch(JSONObject optionsObj , final JSCallback callback, JSCallback progressCallback, final String instanceId, String bundleURL){
-    boolean invaildOption = optionsObj==null || optionsObj.getString("url")==null;
-    if(invaildOption){
-      if(callback != null) {
-        Map<String, Object> resp = new HashMap<>();
-        resp.put("ok", false);
-        resp.put(STATUS_TEXT, Status.ERR_INVALID_REQUEST);
-        callback.invoke(resp);
-      }
-      return;
-    }
-    String method = optionsObj.getString("method");
-    String url = optionsObj.getString("url");
-    JSONObject headers = optionsObj.getJSONObject("headers");
-    String body = optionsObj.getString("body");
-    String type = optionsObj.getString("type");
-    int timeout = optionsObj.getIntValue("timeout");
-
-    WXSDKInstance wxsdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (wxsdkInstance != null) {
-      if (wxsdkInstance.getStreamNetworkHandler() != null) {
-        String localUrl = wxsdkInstance.getStreamNetworkHandler().fetchLocal(url);
-        if (!TextUtils.isEmpty(localUrl)) {
-          url = localUrl;
-        }
-      }
-    }
-
-    if (method != null) method = method.toUpperCase(Locale.ROOT);
-    Options.Builder builder = new Options.Builder()
-        .setMethod(!"GET".equals(method)
-            &&!"POST".equals(method)
-            &&!"PUT".equals(method)
-            &&!"DELETE".equals(method)
-            &&!"HEAD".equals(method)
-            &&!"PATCH".equals(method)?"GET":method)
-        .setUrl(url)
-        .setBody(body)
-        .setType(type)
-        .setTimeout(timeout);
-
-    extractHeaders(headers,builder);
-    final Options options = builder.createOptions();
-    sendRequest(options, new ResponseCallback() {
-      @Override
-      public void onResponse(WXResponse response, Map<String, String> headers) {
-        if(callback != null) {
-          Map<String, Object> resp = new HashMap<>();
-          if(response == null|| "-1".equals(response.statusCode)){
-            resp.put(STATUS,-1);
-            resp.put(STATUS_TEXT,Status.ERR_CONNECT_FAILED);
-          }else {
-            int code = Integer.parseInt(response.statusCode);
-            resp.put(STATUS, code);
-            resp.put("ok", (code >= 200 && code <= 299));
-            if (response.originalData == null) {
-              resp.put("data", null);
-            } else {
-              String respData = readAsString(response.originalData,
-                  headers != null ? getHeader(headers, "Content-Type") : ""
-              );
-              try {
-                resp.put("data", parseData(respData, options.getType()));
-              } catch (JSONException exception) {
-                WXLogUtils.e("", exception);
-                resp.put("ok", false);
-                resp.put("data","{'err':'Data parse failed!'}");
-              }
-            }
-            resp.put(STATUS_TEXT, Status.getStatusText(response.statusCode));
-          }
-          resp.put("headers", headers);
-          WXStateRecord.getInstance().recordAction(instanceId,"stream response code:"+(null!= response?response.statusCode:"null"));
-          callback.invoke(resp);
-        }
-      }
-    }, progressCallback, instanceId, bundleURL);
-  }
-
-  Object parseData(String data, Options.Type type) throws JSONException{
-    if( type == Options.Type.json){
-      return JSONObject.parse(data);
-    }else if( type == Options.Type.jsonp){
-      if(data == null || data.isEmpty()) {
-        return new JSONObject();
-      }
-      int b = data.indexOf("(")+1;
-      int e = data.lastIndexOf(")");
-      if(b ==0 || b >= e || e <= 0){
-        return new JSONObject();
-      }
-
-      data = data.substring(b,e);
-      return JSONObject.parse(data);
-    }else {
-      return data;
-    }
-  }
-
-  static String getHeader(Map<String,String> headers,String key){
-    if(headers == null||key == null){
-      return null;
-    }
-    if(headers.containsKey(key)){
-      return headers.get(key);
-    }else{
-      return headers.get(key.toLowerCase(Locale.ROOT));
-    }
-  }
-
-
-
-  static String readAsString(byte[] data,String cType){
-    String charset = "utf-8";
-    if(cType != null){
-      Matcher matcher = CHARSET_PATTERN.matcher(cType.toLowerCase(Locale.ROOT));
-      if(matcher.find()){
-        charset = matcher.group(1);
-      }
-    }
-    try {
-      return new String(data,charset);
-    } catch (UnsupportedEncodingException e) {
-      WXLogUtils.e("", e);
-      return new String(data);
-    }
-  }
-
-
-  private void extractHeaders(JSONObject headers, Options.Builder builder){
-    //set user-agent
-    String UA = WXHttpUtil.assembleUserAgent(WXEnvironment.getApplication(),WXEnvironment.getConfig());
-    if(headers != null){
-      for (String key : headers.keySet()) {
-        if (key.equals(KEY_USER_AGENT)) {
-          UA = headers.getString(key);
-          continue;
-        }
-        builder.putHeader(key, headers.getString(key));
-      }
-    }
-    builder.putHeader(KEY_USER_AGENT,UA);
-  }
-
-
-  private void sendRequest(Options options,ResponseCallback callback,JSCallback progressCallback,String instanceId, String bundleURL){
-    WXRequest wxRequest = new WXRequest();
-    wxRequest.method = options.getMethod();
-    wxRequest.url = WXSDKManager.getInstance().getURIAdapter().rewrite(bundleURL, URIAdapter.REQUEST,Uri.parse(options.getUrl())).toString();
-    wxRequest.body = options.getBody();
-    wxRequest.timeoutMs = options.getTimeout();
-    wxRequest.instanceId = instanceId;
-
-    if(options.getHeaders()!=null) {
-      if (wxRequest.paramMap == null) {
-        wxRequest.paramMap = options.getHeaders();
-      } else {
-        wxRequest.paramMap.putAll(options.getHeaders());
-      }
-    }
-
-    IWXHttpAdapter adapter = ( mAdapter==null) ? WXSDKManager.getInstance().getIWXHttpAdapter() : mAdapter;
-    if (adapter != null) {
-      adapter.sendRequest(wxRequest, new StreamHttpListener(callback,progressCallback));
-    }else{
-      WXLogUtils.e("WXStreamModule","No HttpAdapter found,request failed.");
-    }
-  }
-
-  private interface ResponseCallback{
-    void onResponse(WXResponse response, Map<String, String> headers);
-  }
-
-  private static class StreamHttpListener implements IWXHttpAdapter.OnHttpListener {
-    private ResponseCallback mCallback;
-    private JSCallback mProgressCallback;
-    private Map<String,Object> mResponse = new HashMap<>();
-    private Map<String,String> mRespHeaders;
-
-    private StreamHttpListener(ResponseCallback callback,JSCallback progressCallback) {
-      mCallback = callback;
-      mProgressCallback = progressCallback;
-    }
-
-
-    @Override
-    public void onHttpStart() {
-      if(mProgressCallback !=null) {
-        mResponse.put("readyState",1);//readyState: number 1 OPENED 2 HEADERS_RECEIVED 3 LOADING
-        mResponse.put("length",0);
-        mProgressCallback.invokeAndKeepAlive(new HashMap<>(mResponse));
-      }
-    }
-
-    @Override
-    public void onHttpUploadProgress(int uploadProgress) {
-
-    }
-
-    @Override
-    public void onHeadersReceived(int statusCode,Map<String,List<String>> headers) {
-      mResponse.put("readyState", 2);
-      mResponse.put("status", statusCode);
-
-      Map<String, String> simpleHeaders = new HashMap<>();
-      if (headers != null) {
-        Iterator<Map.Entry<String, List<String>>> it = headers.entrySet().iterator();
-        while (it.hasNext()) {
-          Map.Entry<String, List<String>> entry = it.next();
-          if (entry.getValue().size() == 0) {
-            continue;
-          } else if (entry.getValue().size() == 1)
-            simpleHeaders.put(entry.getKey() == null ? "_" : entry.getKey(), entry.getValue().get(0));
-          else {
-            simpleHeaders.put(entry.getKey() == null ? "_" : entry.getKey(), entry.getValue().toString());
-          }
-        }
-      }
-
-      mResponse.put("headers", simpleHeaders);
-      mRespHeaders = simpleHeaders;
-      if (mProgressCallback != null) {
-        mProgressCallback.invokeAndKeepAlive(new HashMap<>(mResponse));
-      }
-    }
-
-    @Override
-    public void onHttpResponseProgress(int loadedLength) {
-      mResponse.put("length",loadedLength);
-      if(mProgressCallback!=null){
-        mProgressCallback.invokeAndKeepAlive(new HashMap<>(mResponse));
-      }
-
-    }
-
-    @Override
-    public void onHttpFinish(final WXResponse response) {
-      //compatible with old sendhttp
-      if(mCallback!=null){
-        mCallback.onResponse(response, mRespHeaders);
-      }
-
-      if(WXEnvironment.isApkDebugable()){
-        WXLogUtils.d("WXStreamModule",response!=null && response.originalData!=null?new String(response.originalData):"response data is NUll!");
-      }
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/instance/InstanceOnFireEventInterceptor.java b/android/sdk/src/main/java/com/taobao/weex/instance/InstanceOnFireEventInterceptor.java
deleted file mode 100644
index 3b142f7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/instance/InstanceOnFireEventInterceptor.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.instance;
-
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.ui.WXRenderManager;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by furture on 2018/8/23.
- */
-
-public abstract  class InstanceOnFireEventInterceptor {
-
-    private List<String> listenEvents;
-
-    public InstanceOnFireEventInterceptor() {
-        this.listenEvents = new ArrayList<>();
-    }
-
-    public void addInterceptEvent(String event){
-        if(!listenEvents.contains(event)){
-            this.listenEvents.add(event);
-        }
-    }
-
-    public List<String> getListenEvents() {
-        return listenEvents;
-    }
-
-    public void onInterceptFireEvent(String instanceId, String elementRef, String type, Map<String, Object> params, Map<String, Object> domChanges){
-        if(params == null){
-            return;
-        }
-        if(this.listenEvents.contains(type)){
-            onFireEvent(instanceId, elementRef, type, params, domChanges);
-        }
-    }
-
-    public  abstract void onFireEvent(String instanceId, String elementRef,String type, Map<String, Object> params, Map<String, Object> domChanges);
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/layout/ContentBoxMeasurement.java b/android/sdk/src/main/java/com/taobao/weex/layout/ContentBoxMeasurement.java
deleted file mode 100644
index d25a845..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/layout/ContentBoxMeasurement.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.layout;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import com.taobao.weex.base.CalledByNative;
-import com.taobao.weex.common.Destroyable;
-import com.taobao.weex.ui.component.WXComponent;
-
-import java.io.Serializable;
-import java.lang.ref.WeakReference;
-
-public abstract class ContentBoxMeasurement implements Serializable,Destroyable {
-
-  @Nullable
-  protected WXComponent mComponent;
-
-  protected float mMeasureWidth;
-
-  protected float mMeasureHeight;
-
-  public ContentBoxMeasurement() {
-    mComponent = null;
-  }
-
-  public ContentBoxMeasurement(@NonNull WXComponent component) {
-    this.mComponent = component;
-  }
-
-  /** uiThread = false **/
-  @CalledByNative
-  public final void measure(float width, float height, int widthMeasureMode, int heightMeasureMode) {
-    measureInternal(width, height, widthMeasureMode, heightMeasureMode);
-  }
-
-  /** uiThread = false **/
-  public abstract void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode);
-
-  /** uiThread = false **/
-  @CalledByNative
-  public abstract void layoutBefore();
-
-  /** uiThread = false **/
-  @CalledByNative
-  public abstract void layoutAfter(float computedWidth, float computedHeight);
-
-  @CalledByNative
-  public float getWidth() {
-    return mMeasureWidth;
-  }
-
-  @CalledByNative
-  public float getHeight() {
-    return mMeasureHeight;
-  }
-
-  @Override
-  public void destroy() {
-    mComponent = null;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/layout/MeasureMode.java b/android/sdk/src/main/java/com/taobao/weex/layout/MeasureMode.java
deleted file mode 100644
index fd25f50..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/layout/MeasureMode.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.layout;
-
-import java.io.Serializable;
-
-public class MeasureMode implements Serializable {
-
-  public static int EXACTLY = 1;
-
-  public static int UNSPECIFIED = 0;
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/layout/MeasureSize.java b/android/sdk/src/main/java/com/taobao/weex/layout/MeasureSize.java
deleted file mode 100644
index ad671bf..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/layout/MeasureSize.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.layout;
-
-import java.io.Serializable;
-
-public class MeasureSize implements Serializable{
-  private float width;
-  private float height;
-
-  public float getWidth() {
-    return width;
-  }
-
-  public void setWidth(float width) {
-    this.width = width;
-  }
-
-  public float getHeight() {
-    return height;
-  }
-
-  public void setHeight(float height) {
-    this.height = height;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/layout/measurefunc/TextContentBoxMeasurement.java b/android/sdk/src/main/java/com/taobao/weex/layout/measurefunc/TextContentBoxMeasurement.java
deleted file mode 100755
index 3a22532..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/layout/measurefunc/TextContentBoxMeasurement.java
+++ /dev/null
@@ -1,500 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.layout.measurefunc;
-
-import android.graphics.Canvas;
-import android.os.Build;
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.Editable;
-import android.text.Layout;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.SpannedString;
-import android.text.StaticLayout;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.text.style.AbsoluteSizeSpan;
-import android.text.style.AlignmentSpan;
-import android.text.style.ForegroundColorSpan;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.support.annotation.WorkerThread;
-
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.TextDecorationSpan;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.dom.WXCustomStyleSpan;
-import com.taobao.weex.dom.WXLineHeightSpan;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import com.taobao.weex.layout.MeasureMode;
-import com.taobao.weex.layout.MeasureSize;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXText;
-import com.taobao.weex.ui.component.WXTextDecoration;
-import com.taobao.weex.utils.WXDomUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXResourceUtils;
-
-import java.lang.ref.WeakReference;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-import static com.taobao.weex.dom.WXStyle.UNSET;
-import static com.taobao.weex.utils.WXUtils.isUndefined;
-
-/**
- * Created by miomin on 2018/3/9.
- */
-
-public class TextContentBoxMeasurement extends ContentBoxMeasurement {
-
-  private static final Canvas DUMMY_CANVAS = new Canvas();
-
-  public TextContentBoxMeasurement(WXComponent component) {
-    super(component);
-  }
-
-  class SetSpanOperation {
-
-    protected final int start, end, flag;
-    protected final Object what;
-
-    SetSpanOperation(int start, int end, Object what) {
-      this(start, end, what, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
-    }
-
-    SetSpanOperation(int start, int end, Object what, int flag) {
-      this.start = start;
-      this.end = end;
-      this.what = what;
-      this.flag = flag;
-    }
-
-    public void execute(Spannable sb) {
-      sb.setSpan(what, start, end, flag);
-    }
-  }
-
-  private static final String ELLIPSIS = "\u2026";
-  private boolean mIsColorSet = false;
-  private boolean hasBeenMeasured = false;
-  private int mColor;
-  private int mFontStyle = UNSET;
-  private int mFontWeight = UNSET;
-  private int mNumberOfLines = UNSET;
-  private int mFontSize = UNSET;
-  private int mLineHeight = UNSET;
-  private float previousWidth = Float.NaN;
-  private String mFontFamily = null;
-  private String mText = null;
-  private TextUtils.TruncateAt textOverflow;
-  private Layout.Alignment mAlignment;
-  private WXTextDecoration mTextDecoration = WXTextDecoration.NONE;
-  private TextPaint mTextPaint;
-  private @Nullable
-  Spanned spanned;
-  private @Nullable
-  Layout layout;
-  private AtomicReference<Layout> atomicReference = new AtomicReference<>();
-
-  /**
-   * uiThread = false
-   **/
-  @Override
-  public void layoutBefore() {
-    mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
-    hasBeenMeasured = false;
-    updateStyleAndText();
-    spanned = createSpanned(mText);
-  }
-
-  /**
-   * uiThread = false
-   **/
-  @Override
-  public void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode) {
-    float measureWidth = width, measureHeight = height;
-    hasBeenMeasured = true;
-    float textWidth = getTextWidth(mTextPaint, width, widthMeasureMode == MeasureMode.EXACTLY);
-
-    if (textWidth > 0 && spanned != null) {
-      layout = createLayout(textWidth,null);
-      previousWidth = layout.getWidth();
-      if (Float.isNaN(width)) {
-        measureWidth = layout.getWidth();
-      } else {
-        measureWidth = Math.min(layout.getWidth(), measureWidth);
-      }
-
-      if (Float.isNaN(height)) {
-        measureHeight = layout.getHeight();
-      }
-    } else {
-      if (widthMeasureMode == MeasureMode.UNSPECIFIED) {
-        measureWidth = 0;
-      }
-      if (heightMeasureMode == MeasureMode.UNSPECIFIED) {
-        measureHeight = 0;
-      }
-    }
-    mMeasureWidth = measureWidth;
-    mMeasureHeight = measureHeight;
-  }
-
-  /**
-   * uiThread = false
-   **/
-  @Override
-  public void layoutAfter(float computedWidth, float computedHeight) {
-    if(mComponent!=null) {
-      if (hasBeenMeasured) {
-        if (layout != null &&
-            WXDomUtils
-                .getContentWidth(mComponent.getPadding(), mComponent.getBorder(), computedWidth)
-                != previousWidth) {
-          recalculateLayout(computedWidth);
-        }
-      } else {
-        updateStyleAndText();
-        recalculateLayout(computedWidth);
-      }
-      hasBeenMeasured = false;
-      if (layout != null && !layout.equals(atomicReference.get()) &&
-          Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-        if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
-          warmUpTextLayoutCache(layout);
-        }
-      }
-      swap();
-      WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
-        @Override
-        public void run() {
-          if(mComponent!=null) {
-            mComponent.updateExtra(atomicReference.get());
-          }
-        }
-      }, mComponent.getInstanceId());
-    }
-  }
-
-  private void updateStyleAndText() {
-    updateStyleImp(mComponent.getStyles());
-    mText = WXAttr.getValue(mComponent.getAttrs());
-  }
-
-  /**
-   * Force relayout the text, the text must layout before invoke this method.
-   *
-   * Internal method, do not invoke unless you what what you are doing
-   * @param isRTL
-   */
-  @RestrictTo(Scope.LIBRARY)
-  @WorkerThread
-  public void forceRelayout(){
-    //Generate Spans
-    layoutBefore();
-
-    //Measure
-    measure(previousWidth, Float.NaN, MeasureMode.EXACTLY, MeasureMode.UNSPECIFIED);
-
-    //Swap text layout to UI Thread
-    layoutAfter(previousWidth, Float.NaN);
-  }
-
-  /**
-   * Record the property according to the given style
-   *
-   * @param style the give style.
-   */
-  private void updateStyleImp(Map<String, Object> style) {
-    if (style != null) {
-      if (style.containsKey(Constants.Name.LINES)) {
-        int lines = WXStyle.getLines(style);
-        mNumberOfLines = lines > 0 ? lines : UNSET;
-      }
-      if (style.containsKey(Constants.Name.FONT_SIZE)) {
-        mFontSize = WXStyle.getFontSize(style, mComponent.getViewPortWidth());
-      }
-      if (style.containsKey(Constants.Name.FONT_WEIGHT)) {
-        mFontWeight = WXStyle.getFontWeight(style);
-      }
-      if (style.containsKey(Constants.Name.FONT_STYLE)) {
-        mFontStyle = WXStyle.getFontStyle(style);
-      }
-      if (style.containsKey(Constants.Name.COLOR)) {
-        mColor = WXResourceUtils.getColor(WXStyle.getTextColor(style));
-        mIsColorSet = mColor != Integer.MIN_VALUE;
-      }
-      if (style.containsKey(Constants.Name.TEXT_DECORATION)) {
-        mTextDecoration = WXStyle.getTextDecoration(style);
-      }
-      if (style.containsKey(Constants.Name.FONT_FAMILY)) {
-        mFontFamily = WXStyle.getFontFamily(style);
-      }
-      mAlignment = WXStyle.getTextAlignment(style, mComponent.isLayoutRTL());
-      textOverflow = WXStyle.getTextOverflow(style);
-      int lineHeight = WXStyle.getLineHeight(style, mComponent.getViewPortWidth());
-      if (lineHeight != UNSET) {
-        mLineHeight = lineHeight;
-      }
-    }
-  }
-
-  /**
-   * Update {@link #spanned} according to the give charSequence and styles
-   *
-   * @param text the give raw text.
-   * @return an Spanned contains text and spans
-   */
-  protected
-  @NonNull
-  Spanned createSpanned(String text) {
-    if (!TextUtils.isEmpty(text)) {
-      SpannableString spannable = new SpannableString(text);
-      updateSpannable(spannable, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
-      return spannable;
-    }
-    return new SpannableString("");
-  }
-
-  protected void updateSpannable(Spannable spannable, int spanFlag) {
-    int end = spannable.length();
-    if (mFontSize == UNSET) {
-      mTextPaint.setTextSize(WXText.sDEFAULT_SIZE);
-    }
-    else{
-      mTextPaint.setTextSize(mFontSize);
-    }
-
-    if (mLineHeight != UNSET) {
-      setSpan(spannable, new WXLineHeightSpan(mLineHeight), 0, end, spanFlag);
-    }
-
-    setSpan(spannable, new AlignmentSpan.Standard(mAlignment), 0, end, spanFlag);
-
-    if (mFontStyle != UNSET || mFontWeight != UNSET || mFontFamily != null) {
-      setSpan(spannable, new WXCustomStyleSpan(mFontStyle, mFontWeight, mFontFamily), 0, end, spanFlag);
-    }
-
-    if (mIsColorSet) {
-      mTextPaint.setColor(mColor);
-    }
-
-    if (mTextDecoration == WXTextDecoration.UNDERLINE || mTextDecoration == WXTextDecoration.LINETHROUGH) {
-      setSpan(spannable, new TextDecorationSpan(mTextDecoration), 0, end, spanFlag);
-    }
-  }
-
-  private void setSpan(Spannable spannable, Object what, int start, int end, int spanFlag){
-    spannable.setSpan(what, start, end, spanFlag);
-  }
-
-  /**
-   * Get text width according to constrain of outerWidth with and forceToDesired
-   *
-   * @param textPaint      paint used to measure text
-   * @param outerWidth     the width that css-layout desired.
-   * @param forceToDesired if set true, the return value will be outerWidth, no matter what the width
-   *                       of text is.
-   * @return if forceToDesired is false, it will be the minimum value of the width of text and
-   * outerWidth in case of outerWidth is defined, in other case, it will be outer width.
-   */
-  private float getTextWidth(TextPaint textPaint, float outerWidth, boolean forceToDesired) {
-    if (mText == null) {
-      if (forceToDesired) {
-        return outerWidth;
-      }
-      return 0;
-    }
-    else {
-      float textWidth;
-      if (forceToDesired) {
-        textWidth = outerWidth;
-      } else {
-        float desiredWidth = Layout.getDesiredWidth(spanned, textPaint);
-        if (isUndefined(outerWidth) || desiredWidth < outerWidth) {
-          textWidth = desiredWidth;
-        } else {
-          textWidth = outerWidth;
-        }
-      }
-      return textWidth;
-    }
-  }
-
-  /**
-   * Update layout according to {@link #mText} and span
-   *
-   * @param width          the specified width.
-   * @param forceWidth     If true, force the text width to the specified width, otherwise, text width
-   *                       may equals to or be smaller than the specified width.
-   * @param previousLayout the result of previous layout, could be null.
-   */
-  private
-  @NonNull
-  Layout createLayout(final float textWidth, @Nullable Layout previousLayout) {
-    Layout layout;
-    if (previousWidth != textWidth || previousLayout == null) {
-      layout = new StaticLayout(spanned, mTextPaint, (int) Math.ceil(textWidth),
-              Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
-    } else {
-      layout = previousLayout;
-    }
-    if (mNumberOfLines != UNSET && mNumberOfLines > 0 && mNumberOfLines < layout.getLineCount()) {
-      int lastLineStart, lastLineEnd;
-      lastLineStart = layout.getLineStart(mNumberOfLines - 1);
-      lastLineEnd = layout.getLineEnd(mNumberOfLines - 1);
-      if (lastLineStart < lastLineEnd) {
-        SpannableStringBuilder builder = null;
-        if (lastLineStart > 0) {
-          builder = new SpannableStringBuilder(spanned.subSequence(0, lastLineStart));
-        } else {
-          builder = new SpannableStringBuilder();
-        }
-        Editable lastLine = new SpannableStringBuilder(spanned.subSequence(lastLineStart, lastLineEnd));
-        builder.append(truncate(lastLine, mTextPaint, (int) Math.ceil(textWidth), textOverflow));
-        adjustSpansRange(spanned, builder);
-        spanned = builder;
-        return new StaticLayout(spanned, mTextPaint, (int) Math.ceil(textWidth),
-                Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
-      }
-    }
-    return layout;
-  }
-
-  /**
-   * Truncate the source span to the specified lines.
-   * Caller of this method must ensure that the lines of text is <strong>greater than desired lines and need truncate</strong>.
-   * Otherwise, unexpected behavior may happen.
-   *
-   * @param source     The source span.
-   * @param paint      the textPaint
-   * @param desired    specified lines.
-   * @param truncateAt truncate method, null value means clipping overflow text directly, non-null value means using ellipsis strategy to clip
-   * @return The spans after clipped.
-   */
-  private
-  @NonNull
-  Spanned truncate(@Nullable Editable source, @NonNull TextPaint paint,
-                   int desired, @Nullable TextUtils.TruncateAt truncateAt) {
-    Spanned ret = new SpannedString("");
-    if (!TextUtils.isEmpty(source) && source.length() > 0) {
-      if (truncateAt != null) {
-        source.append(ELLIPSIS);
-        Object[] spans = source.getSpans(0, source.length(), Object.class);
-        for (Object span : spans) {
-          int start = source.getSpanStart(span);
-          int end = source.getSpanEnd(span);
-          if (start == 0 && end == source.length() - 1) {
-            source.removeSpan(span);
-            source.setSpan(span, 0, source.length(), source.getSpanFlags(span));
-          }
-        }
-      }
-
-      StaticLayout layout;
-      int startOffset;
-
-      while (source.length() > 1) {
-        startOffset = source.length() - 1;
-        if (truncateAt != null) {
-          startOffset -= 1;
-        }
-        source.delete(startOffset, startOffset + 1);
-        layout = new StaticLayout(source, paint, desired, Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
-        if (layout.getLineCount() <= 1) {
-          ret = source;
-          break;
-        }
-      }
-    }
-    return ret;
-  }
-
-  /**
-   * Adjust span range after truncate due to the wrong span range during span copy and slicing.
-   *
-   * @param beforeTruncate The span before truncate
-   * @param afterTruncate  The span after truncate
-   */
-  private void adjustSpansRange(@NonNull Spanned beforeTruncate, @NonNull Spannable afterTruncate) {
-    Object[] spans = beforeTruncate.getSpans(0, beforeTruncate.length(), Object.class);
-    for (Object span : spans) {
-      int start = beforeTruncate.getSpanStart(span);
-      int end = beforeTruncate.getSpanEnd(span);
-      if (start == 0 && end == beforeTruncate.length()) {
-        afterTruncate.removeSpan(span);
-        afterTruncate.setSpan(span, 0, afterTruncate.length(), beforeTruncate.getSpanFlags(span));
-      }
-    }
-  }
-
-  private void recalculateLayout(float computedWidth) {
-    float contentWidth = WXDomUtils.getContentWidth(mComponent.getPadding(), mComponent.getBorder(), computedWidth);
-    if (contentWidth > 0) {
-      spanned = createSpanned(mText);
-      if (spanned != null) {
-        layout = createLayout(contentWidth, layout);
-        previousWidth = layout.getWidth();
-      } else {
-        previousWidth = 0;
-      }
-    }
-  }
-
-  /**
-   * As warming up TextLayoutCache done in the DOM thread may manipulate UI operation,
-   * there may be some exception, in which case the exception is ignored. After all,
-   * this is just a warm up operation.
-   *
-   * @return false for warm up failure, otherwise returns true.
-   */
-  private boolean warmUpTextLayoutCache(Layout layout) {
-    boolean result;
-    try {
-      layout.draw(DUMMY_CANVAS);
-      result = true;
-    } catch (Exception e) {
-      WXLogUtils.eTag("TextWarmUp", e);
-      result = false;
-    }
-    return result;
-  }
-
-  /**
-   * Move the reference of current layout to the {@link AtomicReference} for further use,
-   * then clear current layout.
-   */
-  private void swap() {
-    if (layout != null) {
-      atomicReference.set(layout);
-      layout = null;
-    }
-    hasBeenMeasured = false;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/IApmGenerator.java b/android/sdk/src/main/java/com/taobao/weex/performance/IApmGenerator.java
deleted file mode 100644
index face350..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/performance/IApmGenerator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.performance;
-
-public interface IApmGenerator {
-    /**
-     * @param type apm type
-     * @return impl
-     */
-    IWXApmMonitorAdapter generateApmInstance(String type);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/IWXAnalyzer.java b/android/sdk/src/main/java/com/taobao/weex/performance/IWXAnalyzer.java
deleted file mode 100644
index cbd170c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/performance/IWXAnalyzer.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.performance;
-
-
-/**
- * @author zhongcang
- * @date 2018/2/28
- */
-
-public interface IWXAnalyzer {
-
-  /**
-   *
-   * @param group   dataGroup
-   * @param module  dataModule in group
-   * @param type    dataType
-   * @param data   data (json)
-   */
-  void transfer(String group, String module, String type, String data);
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/IWXApmMonitorAdapter.java b/android/sdk/src/main/java/com/taobao/weex/performance/IWXApmMonitorAdapter.java
deleted file mode 100644
index 1fe198e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/performance/IWXApmMonitorAdapter.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.performance;
-
-public interface IWXApmMonitorAdapter {
-
-    /**
-     * start record
-     *
-     * @param instanceId instanceId
-     */
-    void onStart(String instanceId);
-
-    /**
-     * end record
-     */
-    void onEnd();
-
-    /**
-     * record event
-     */
-    void onEvent(String name, Object value);
-
-    /**
-     * record stage
-     */
-    void onStage(String name, long timestamp);
-
-    /**
-     * record property
-     */
-    void addProperty(String key, Object value);
-
-    /**
-     * record statistic
-     */
-    void addStats(String key, double value);
-
-    /**
-     * record subProcedure stage
-     */
-
-    void onSubProcedureStage(String procedureName, String stageName);
-
-    /**
-     * record SubProcedure event
-     */
-
-    void onSubProcedureEvent(String procedureName, String eventName);
-
-    /**
-     * record subProcedure stats
-     */
-    void setSubProcedureStats(String procedureName, String name, double value);
-
-    /**
-     * record subProcedure properties
-     */
-    void setSubProcedureProperties(String procedureName, String name, Object value);
-
-    void onAppear();
-
-    void onDisappear();
-
-    String parseReportUrl(String originUrl);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/WXAnalyzerDataTransfer.java b/android/sdk/src/main/java/com/taobao/weex/performance/WXAnalyzerDataTransfer.java
deleted file mode 100644
index 194046c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/performance/WXAnalyzerDataTransfer.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.performance;
-
-import java.util.Iterator;
-import java.util.List;
-
-import android.util.Log;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.bridge.WXJSObject;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXJSExceptionInfo;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXUtils;
-import org.json.JSONObject;
-
-/**
- * @author zhongcang
- * @date 2018/2/28
- */
-
-public class WXAnalyzerDataTransfer {
-
-  private static final String GROUP = "WXAnalyzer";
-  private static final String MODULE_ERROR = "WXError";
-  private static final String MODULE_WX_APM = "wxapm";
-  public static boolean isOpenPerformance = false;
-  public static final String INTERACTION_TAG = "wxInteractionAnalyzer";
-  private static boolean sOpenInteractionLog;
-
-
-  public static void transferPerformance(String instanceId,String type,String key,Object value)
-  {
-      if (!isOpenPerformance){
-          return;
-      }
-      if (sOpenInteractionLog && "stage".equals(type)){
-          Log.d(INTERACTION_TAG, "[client][stage]"+instanceId+","+key+","+value);
-      }
-      List<IWXAnalyzer> transferList = WXSDKManager.getInstance().getWXAnalyzerList();
-      if (null == transferList || transferList.size() == 0) {
-          return;
-      }
-
-      WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-      if (null == instance){
-          return;
-      }
-
-      String data;
-      try {
-        data = new JSONObject().put(key,value).toString();
-      }catch (Exception e){
-        e.printStackTrace();
-        return;
-      }
-
-      Iterator<IWXAnalyzer> itr = transferList.iterator();
-      while (itr.hasNext()){
-          IWXAnalyzer item = itr.next();
-          item.transfer(MODULE_WX_APM, instance.getInstanceId(), type, data);
-      }
-  }
-
-  public static void transferInteractionInfo(WXComponent targetComponent){
-    if (!isOpenPerformance){
-      return;
-    }
-
-    List<IWXAnalyzer> transferList = WXSDKManager.getInstance().getWXAnalyzerList();
-    if (null == transferList || transferList.size() == 0) {
-      return;
-    }
-    long renderOriginDiffTime = WXUtils.getFixUnixTime() - targetComponent.getInstance().getWXPerformance().renderUnixTimeOrigin;
-    String data;
-    try{
-      data = new JSONObject()
-          .put("renderOriginDiffTime",renderOriginDiffTime)
-          .put("type",targetComponent.getComponentType())
-          .put("ref",targetComponent.getRef())
-          .put("style",targetComponent.getStyles())
-          .put("attrs",targetComponent.getAttrs())
-          .toString();
-    }catch (Exception e){
-      e.printStackTrace();
-      return;
-    }
-    for (IWXAnalyzer transfer : transferList) {
-      transfer.transfer(MODULE_WX_APM, targetComponent.getInstanceId(), "wxinteraction", data);
-    }
-  }
-
-
-  public static void transferError(WXJSExceptionInfo exceptionInfo, String instanceId) {
-    if (!WXEnvironment.isApkDebugable()) {
-      return;
-    }
-    List<IWXAnalyzer> transferList = WXSDKManager.getInstance().getWXAnalyzerList();
-    if (null == transferList || transferList.size() == 0) {
-      return;
-    }
-
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (null == instance) {
-      return;
-    }
-    WXErrorCode errorCode = exceptionInfo.getErrCode();
-    String data = "";
-    try {
-      data = new JSONObject()
-              .put("instanceId", instanceId)
-              .put("url", instance.getBundleUrl())
-              .put("errorCode", errorCode.getErrorCode())
-              .put("errorMsg", errorCode.getErrorMsg())
-              .put("errorGroup", errorCode.getErrorGroup())
-              .toString();
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-    for (IWXAnalyzer transfer : transferList) {
-      transfer.transfer(GROUP, MODULE_ERROR, errorCode.getErrorType().toString(), data);
-    }
-  }
-
-  public static void switchInteractionLog(final boolean isOpen){
-      if ( sOpenInteractionLog == isOpen || !WXEnvironment.JsFrameworkInit){
-          return;
-      }
-      sOpenInteractionLog = isOpen;
-      //for jsfm && jsengin
-      //TODO wait for JSFramework
-//      WXBridgeManager.getInstance().post(new Runnable() {
-//          @Override
-//          public void run() {
-//              WXJSObject[] args = {new WXJSObject(isOpen?1:0)};
-//              WXBridgeManager.getInstance().invokeExecJS(
-//                  "",
-//                  null,
-//                  "switchInteractionLog",
-//                  args,
-//                  false);
-//          }
-//      });
-      //for weex_core
-      WXBridgeManager.getInstance().registerCoreEnv("switchInteractionLog",String.valueOf(isOpen));
-  }
-
-  public static boolean isInteractionLogOpen(){
-     return sOpenInteractionLog;
-  }
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java b/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java
deleted file mode 100644
index 4f99696..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java
+++ /dev/null
@@ -1,683 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.performance;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-import android.util.Log;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXPerformance;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-public class WXInstanceApm {
-
-    public static final String WEEX_PAGE_TOPIC = "weex_page";
-
-    /************** properties *****************/
-    public static final String KEY_PROPERTIES_ERROR_CODE = "wxErrorCode";
-    //public static final String KEY_PAGE_PROPERTIES_LAUNCH_ID = "wxLaunchId";
-    public static final String KEY_PAGE_PROPERTIES_BIZ_ID = "wxBizID";
-    public static final String KEY_PAGE_PROPERTIES_BUBDLE_URL = "wxBundleUrl";
-    public static final String KEY_PAGE_PROPERTIES_JSLIB_VERSION = "wxJSLibVersion";
-    public static final String KEY_PAGE_PROPERTIES_WEEX_VERSION = "wxSDKVersion";
-    public static final String KEY_PAGE_PROPERTIES_REQUEST_TYPE = "wxRequestType";
-    public static final String KEY_PAGE_PROPERTIES_CACHE_TYPE = "wxCacheType";
-    public static final String KEY_PAGE_PROPERTIES_CACHE_INFO = "wxZCacheInfo";
-    public static final String KEY_PAGE_PROPERTIES_JS_FM_INI = "wxJsFrameworkInit";
-    public static final String KEY_PAGE_PROPERTIES_CONTAINER_NAME = "wxContainerName";
-    public static final String KEY_PAGE_PROPERTIES_INSTANCE_TYPE = "wxInstanceType";
-    public static final String KEY_PAGE_PROPERTIES_PARENT_PAGE = "wxParentPage";
-    public static final String KEY_PAGE_PROPERTIES_BUNDLE_TYPE = "wxBundleType";
-    public static final String KEY_PAGE_PROPERTIES_RENDER_TYPE = "wxRenderType";
-    public static final String KEY_PAGE_PROPERTIES_UIKIT_TYPE = "wxUIKitType";
-
-    /************** stages *****************/
-    public static final String KEY_PAGE_STAGES_CONTAINER_READY = "wxContainerReady";
-    public static final String KEY_PAGE_STAGES_DOWN_BUNDLE_START = "wxStartDownLoadBundle";
-    public static final String KEY_PAGE_STAGES_DOWN_BUNDLE_END = "wxEndDownLoadBundle";
-    public static final String KEY_PAGE_STAGES_RENDER_ORGIGIN = "wxRenderTimeOrigin";
-    public static final String KEY_PAGE_STAGES_LOAD_BUNDLE_START = "wxStartLoadBundle";
-    public static final String KEY_PAGE_STAGES_LOAD_BUNDLE_END = "wxEndLoadBundle";
-    public static final String KEY_PAGE_STAGES_FIRST_INTERACTION_VIEW = "wxFirstInteractionView";
-    public static final String KEY_PAGE_STAGES_CREATE_FINISH= "wxJSBundleCreateFinish";
-    public static final String KEY_PAGE_STAGES_FSRENDER = "wxFsRender";
-    public static final String KEY_PAGE_STAGES_NEW_FSRENDER = "wxNewFsRender";
-    public static final String KEY_PAGE_STAGES_END_EXCUTE_BUNDLE = "wxEndExecuteBundle";
-    public static final String KEY_PAGE_STAGES_INTERACTION = "wxInteraction";
-    public static final String KEY_PAGE_STAGES_DESTROY = "wxDestroy";
-
-    //Custom preprocessing start, called when activity created or other time. Called by other activity
-    public static final String KEY_PAGE_STAGES_CUSTOM_PREPROCESS_START = "wxCustomPreprocessStart";
-    //Custom preprocessing end, called when you'are able to start weex render. Called by other activity
-    public static final String KEY_PAGE_STAGES_CUSTOM_PREPROCESS_END = "wxCustomPreprocessEnd";
-
-    /************** stats *****************/
-    public static final String KEY_PAGE_STATS_BUNDLE_SIZE = "wxBundleSize";
-    public static final String KEY_PAGE_STATS_FS_CALL_JS_TIME = "wxFSCallJsTotalTime";
-    public static final String KEY_PAGE_STATS_FS_CALL_JS_NUM = "wxFSCallJsTotalNum";
-    public static final String KEY_PAGE_STATS_FS_TIMER_NUM = "wxFSTimerCount";
-    public static final String KEY_PAGE_STATS_FS_CALL_NATIVE_TIME = "wxFSCallNativeTotalTime";
-    public static final String KEY_PAGE_STATS_FS_CALL_NATIVE_NUM = "wxFSCallNativeTotalNum";
-    public static final String KEY_PAGE_STATS_FS_CALL_EVENT_NUM = "wxFSCallEventTotalNum";
-    public static final String KEY_PAGE_STATS_FS_REQUEST_NUM = "wxFSRequestNum";
-    public static final String KEY_PAGE_STATS_CELL_EXCEED_NUM = "wxCellExceedNum";
-    public static final String KEY_PAGE_STATS_MAX_DEEP_VIEW = "wxMaxDeepViewLayer";
-    public static final String KEY_PAGE_STATS_MAX_DEEP_DOM = "wxMaxDeepVDomLayer";
-    public static final String KEY_PAGE_STATS_MAX_COMPONENT_NUM = "wxMaxComponentCount";
-    public static final String KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT = "wxWrongImgSizeCount";
-    public static final String KEY_PAGE_STATS_EMBED_COUNT = "wxEmbedCount";
-    public static final String KEY_PAGE_STATS_LARGE_IMG_COUNT = "wxLargeImgMaxCount";
-    public static final String KEY_PAGE_STATS_BODY_RATIO = "wxBodyRatio";
-    public static final String KEY_PAGE_STATS_SCROLLER_NUM = "wxScrollerCount";
-    public static final String KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM = "wxCellDataUnRecycleCount";
-    public static final String KEY_PAGE_STATS_CELL_UN_RE_USE_NUM = "wxCellUnReUseCount";
-    public static final String KEY_PAGE_STATS_IMG_UN_RECYCLE_NUM = "wxImgUnRecycleCount";
-
-    public static final String KEY_PAGE_STATS_I_SCREEN_VIEW_COUNT = "wxInteractionScreenViewCount";
-    public static final String KEY_PAGE_STATS_I_ALL_VIEW_COUNT = "wxInteractionAllViewCount";
-    public static final String KEY_PAGE_STATS_I_COMPONENT_CREATE_COUNT = "wxInteractionComponentCreateCount";
-    public static final String KEY_PAGE_ANIM_BACK_NUM = "wxAnimationInBackCount";
-    public static final String KEY_PAGE_TIMER_BACK_NUM = "wxTimerInBackCount";
-    public static final String KEY_PAGE_STATS_ACTUAL_DOWNLOAD_TIME = "wxActualNetworkTime";
-
-    public static final String KEY_PAGE_STATS_IMG_LOAD_NUM = "wxImgLoadCount";
-    public static final String KEY_PAGE_STATS_IMG_LOAD_SUCCESS_NUM = "wxImgLoadSuccessCount";
-    public static final String KEY_PAGE_STATS_IMG_LOAD_FAIL_NUM = "wxImgLoadFailCount";
-    public static final String KEY_PAGE_STATS_NET_NUM = "wxNetworkRequestCount";
-    public static final String KEY_PAGE_STATS_NET_SUCCESS_NUM = "wxNetworkRequestSuccessCount";
-    public static final String KEY_PAGE_STATS_NET_FAIL_NUM = "wxNetworkRequestFailCount";
-    public static final String KEY_PAGE_STATS_JSLIB_INIT_TIME = "wxJSLibInitTime";
-    public static final String KEY_PAGE_STATS_VIEW_CREATE_COST = "wxViewCost";
-    public static final String KEY_PAGE_STATS_COMPONENT_CREATE_COST = "wxComponentCost";
-    public static final String KEY_PAGE_STATS_EXECUTE_JS_CALLBACK_COST = "wxExecJsCallBack";
-    public static final String KEY_PAGE_STATS_LAYOUT_TIME = "wxLayoutTime";
-
-
-    /************** value *****************/
-    public static final String VALUE_ERROR_CODE_DEFAULT = "0";
-    public static final String VALUE_BUNDLE_LOAD_LENGTH = "wxLoadedLength";
-
-    private String mInstanceId;
-    private IWXApmMonitorAdapter apmInstance;
-    private Map<String, Double> recordStatsMap;
-    public final Map<String, Long> stageMap;
-    private Map<String,Object> mPropertiesMap;
-    private boolean isFSEnd;
-    private boolean mHasInit = false;
-    private boolean mEnd = false;
-    private boolean hasRecordFistInteractionView =false;
-    public final Map<String,Object> extInfo;
-    public boolean forceStopRecordInteraction = false;
-    public Rect instanceRect;
-    public String reportPageName;
-    public boolean hasReportLayerOverDraw = false;
-    public boolean hasAddView;
-    private Handler mUIHandler;
-
-    public Set<String> exceptionRecord = new CopyOnWriteArraySet<String>();
-
-    private double interactionLayoutTime;
-    public long componentCreateTime;
-    private long interactionComponentCreateTime;
-    public long viewCreateTime;
-    private long interactionViewCreateTime;
-    //next version
-    private long wxExecJsCallBackTime;
-    private long interactionJsCallBackTime;
-
-
-    private boolean mHasRecordDetailData = false;
-
-    /**
-     * send performance value to js
-     **/
-    private boolean hasSendInteractionToJS = false;
-    public volatile boolean isReady = true;
-
-    public WXInstanceApm(String instanceId) {
-        mInstanceId = instanceId;
-        extInfo = new ConcurrentHashMap<>();
-        stageMap = new ConcurrentHashMap<>();
-        mUIHandler = new Handler(Looper.getMainLooper());
-        recordStatsMap = new ConcurrentHashMap<>();
-        mPropertiesMap = new ConcurrentHashMap<>();
-        IApmGenerator generator = WXSDKManager.getInstance().getApmGenerater();
-        if (null != generator) {
-            apmInstance = generator.generateApmInstance(WEEX_PAGE_TOPIC);
-        }
-    }
-
-    public void onInstanceReady(boolean isPreDownLoad){
-        this.isReady = true;
-        if (isPreDownLoad){
-            onStage(KEY_PAGE_STAGES_DOWN_BUNDLE_START);
-        }
-        doInit();
-        for (Map.Entry<String,Long> stage:stageMap.entrySet()){
-            sendStageInfo(stage.getKey(),stage.getValue());
-        }
-        for (Map.Entry<String,Double> stats:recordStatsMap.entrySet()){
-           sendStats(stats.getKey(),stats.getValue());
-        }
-        for (Map.Entry<String,Object> p:mPropertiesMap.entrySet()){
-           sendProperty(p.getKey(),p.getValue());
-        }
-    }
-
-    /**
-     * record event
-     */
-    public void onEvent(String name, Object value) {
-        if (null == apmInstance) {
-            return;
-        }
-        apmInstance.onEvent(name, value);
-    }
-
-    /**
-     * record stage
-     */
-    public void onStage(String name) {
-        long time =  WXUtils.getFixUnixTime();
-        onStageWithTime(name,time);
-    }
-
-    /**
-     *
-     * @param name stage
-     * @param time unixTime ,plz use WXUtils.getFixUnixTime
-     */
-    public void onStageWithTime(String name,long time){
-        if (mEnd){
-            return;
-        }
-        if (null == name){
-            return;
-        }
-        stageMap.put(name,time);
-        if (isReady){
-            sendStageInfo(name,time);
-        }
-    }
-
-    private void sendStageInfo(String name,long time){
-        if(WXAnalyzerDataTransfer.isOpenPerformance){
-            WXAnalyzerDataTransfer.transferPerformance(mInstanceId,"stage",name,time);
-        }
-
-        if (KEY_PAGE_STAGES_RENDER_ORGIGIN.equalsIgnoreCase(name)){
-            mUIHandler.postDelayed(jsPerformanceCallBack,8000);
-        }
-
-        if (null == apmInstance) {
-            return;
-        }
-
-        apmInstance.onStage(name, time);
-    }
-
-    private Runnable jsPerformanceCallBack = new Runnable() {
-        @Override
-        public void run() {
-            sendPerformanceToJS();
-        }
-    };
-
-    /**
-     * record property
-     */
-    public void addProperty(String key, Object value) {
-        if (mEnd){
-            return;
-        }
-        if (null == key || null == value){
-            return;
-        }
-        mPropertiesMap.put(key,value);
-        if (isReady){
-            sendProperty(key,value);
-        }
-    }
-
-    private void sendProperty(String key,Object value){
-        if(WXAnalyzerDataTransfer.isOpenPerformance){
-            WXAnalyzerDataTransfer.transferPerformance(mInstanceId,"properties",key,value);
-        }
-
-        if (null == apmInstance) {
-            return;
-        }
-        apmInstance.addProperty(key, value);
-    }
-
-    /**
-     * record statistic
-     */
-    public void addStats(String key, double value) {
-        if (mEnd){
-            return;
-        }
-        if (null == key){
-            return;
-        }
-        recordStatsMap.put(key,value);
-        if (isReady){
-            sendStats(key,value);
-        }
-    }
-
-    private void sendStats(String key,double value){
-        if(WXAnalyzerDataTransfer.isOpenPerformance){
-            WXAnalyzerDataTransfer.transferPerformance(mInstanceId,"stats",key,value);
-        }
-
-        if (null == apmInstance) {
-            return;
-        }
-        apmInstance.addStats(key, value);
-    }
-
-
-    public boolean hasInit(){
-        return mHasInit;
-    }
-
-    /**
-     * start record
-     */
-    public void doInit() {
-        if (!isReady){
-            return;
-        }
-        if (mHasInit){
-            return;
-        }
-        mHasInit = true;
-        if (null == apmInstance) {
-            return;
-        }
-        apmInstance.onStart(mInstanceId);
-        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(mInstanceId);
-        String url = null == instance ? "unKnowUrl" : instance.getBundleUrl();
-        addProperty(KEY_PAGE_PROPERTIES_BUBDLE_URL, url);
-        addProperty(KEY_PROPERTIES_ERROR_CODE, VALUE_ERROR_CODE_DEFAULT);
-        addProperty(KEY_PAGE_PROPERTIES_JSLIB_VERSION, WXEnvironment.JS_LIB_SDK_VERSION);
-        addProperty(KEY_PAGE_PROPERTIES_WEEX_VERSION, WXEnvironment.WXSDK_VERSION);
-        addProperty(KEY_PAGE_PROPERTIES_WEEX_VERSION, WXEnvironment.WXSDK_VERSION);
-        addStats("wxReInitCount",WXBridgeManager.reInitCount);
-        if (null != instance){
-            addProperty(KEY_PAGE_PROPERTIES_UIKIT_TYPE, instance.getRenderType());
-        }
-
-        addProperty("wxUseRuntimeApi",WXEnvironment.sUseRunTimeApi);
-        if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER
-                || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
-            addProperty(KEY_PAGE_PROPERTIES_RENDER_TYPE, WXEnvironment.EAGLE);
-        }
-        if (null != instance) {
-            for (Map.Entry<String, String> entry : instance.getContainerInfo().entrySet()) {
-                addProperty(entry.getKey(), entry.getValue());
-            }
-        }
-    }
-
-    public void setPageName(String pageName) {
-        if (TextUtils.isEmpty(pageName)) {
-            WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(mInstanceId);
-            if (null != instance) {
-                pageName = instance.getContainerInfo().get(KEY_PAGE_PROPERTIES_CONTAINER_NAME);
-            }
-        }
-        reportPageName = null == apmInstance?pageName:apmInstance.parseReportUrl(pageName);
-        reportPageName = TextUtils.isEmpty(reportPageName) ? "emptyPageName" : reportPageName;
-        addProperty(KEY_PAGE_PROPERTIES_BIZ_ID, reportPageName);
-    }
-
-    public void onAppear(){
-        if (null == apmInstance) {
-            return;
-        }
-        apmInstance.onAppear();
-    }
-
-    public void onDisAppear(){
-        if (null == apmInstance) {
-            return;
-        }
-        apmInstance.onDisappear();
-    }
-
-    /**
-     * end record
-     */
-    public void onEnd() {
-        if (null == apmInstance || mEnd) {
-            return;
-        }
-        new Handler(Looper.getMainLooper()).removeCallbacks(delayCollectDataTask);
-        recordPerformanceDetailData();
-        exceptionRecord.clear();
-        mUIHandler.removeCallbacks(jsPerformanceCallBack);
-        onStage(KEY_PAGE_STAGES_DESTROY);
-        if (mHasInit && null != apmInstance){
-            apmInstance.onEnd();
-        }
-        mEnd = true;
-        if (WXEnvironment.isApkDebugable()){
-            printLog();
-        }
-    }
-
-    public void doDelayCollectData(){
-        new Handler(Looper.getMainLooper()).postDelayed(delayCollectDataTask,8000);
-    }
-
-    private Runnable delayCollectDataTask = new Runnable() {
-        @Override
-        public void run() {
-            recordPerformanceDetailData();
-        }
-    };
-
-
-    private void printLog(){
-        Long startDownLoad = stageMap.get(KEY_PAGE_STAGES_DOWN_BUNDLE_START);
-        Long endDownLoad = stageMap.get(KEY_PAGE_STAGES_DOWN_BUNDLE_END);
-        Long interaction = stageMap.get(KEY_PAGE_STAGES_INTERACTION);
-        Long containerReady = stageMap.get(KEY_PAGE_STAGES_CONTAINER_READY);
-        if (null != endDownLoad && null != startDownLoad){
-            WXLogUtils.d("test->", "downLoadTime: "+ (endDownLoad - startDownLoad));
-        }
-        if (null != endDownLoad && null != interaction){
-            WXLogUtils.d("test->", "renderTime: "+ (interaction - endDownLoad));
-        }
-        if (null != containerReady && null !=interaction){
-            WXLogUtils.d("test->", "showTime: "+ (interaction - containerReady));
-        }
-
-    }
-
-    public void arriveNewFsRenderTime(){
-        if (null == apmInstance){
-            return;
-        }
-        onStage(WXInstanceApm.KEY_PAGE_STAGES_NEW_FSRENDER);
-    }
-
-    public void arriveFSRenderTime() {
-        if (null == apmInstance){
-            return;
-        }
-        isFSEnd = true;
-        onStage(WXInstanceApm.KEY_PAGE_STAGES_FSRENDER);
-    }
-
-    public void arriveInteraction(WXComponent targetComponent) {
-        if (null == apmInstance || null == targetComponent || targetComponent.getInstance() == null) {
-            return;
-        }
-
-        if (WXAnalyzerDataTransfer.isOpenPerformance){
-            WXAnalyzerDataTransfer.transferInteractionInfo(targetComponent);
-        }
-
-
-        if (null == apmInstance){
-            return;
-        }
-
-        WXPerformance performanceRecord = targetComponent.getInstance().getWXPerformance();
-        if (null == performanceRecord){
-            return;
-        }
-
-        long curTime = WXUtils.getFixUnixTime();
-
-        if (WXAnalyzerDataTransfer.isInteractionLogOpen()){
-            Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][wxinteraction]"
-                + targetComponent.getInstance().getInstanceId()
-                +","+targetComponent.getComponentType()
-                +","+targetComponent.getRef()
-                +","+targetComponent.getStyles()
-                +","+targetComponent.getAttrs()
-            );
-        }
-
-        if (!hasRecordFistInteractionView){
-            onStage(KEY_PAGE_STAGES_FIRST_INTERACTION_VIEW);
-            hasRecordFistInteractionView = true;
-        }
-        if (forceStopRecordInteraction){
-            return;
-        }
-        long now = WXUtils.getFixUnixTime();
-        if (now - preUpdateTime > 50){
-            //for performance, reduce jni calls
-            WXBridgeManager.getInstance().onInteractionTimeUpdate(mInstanceId);
-            preUpdateTime = now;
-        }
-
-        interactionComponentCreateTime = componentCreateTime;
-        interactionViewCreateTime = viewCreateTime;
-        Double layoutTime = recordStatsMap.get("wxLayoutTime");
-        interactionLayoutTime = layoutTime ==null? 0:layoutTime;
-
-        performanceRecord.interactionTime = curTime - performanceRecord.renderUnixTimeOrigin;
-        performanceRecord.interactionRealUnixTime = System.currentTimeMillis();
-        onStageWithTime(KEY_PAGE_STAGES_INTERACTION,curTime);
-
-        updateDiffStats(KEY_PAGE_STATS_I_SCREEN_VIEW_COUNT, 1);
-        updateMaxStats(KEY_PAGE_STATS_I_ALL_VIEW_COUNT, performanceRecord.localInteractionViewAddCount);
-        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
-        if (null != instance) {
-            updateMaxStats(KEY_PAGE_STATS_I_COMPONENT_CREATE_COUNT, instance.getWXPerformance().componentCount);
-        }
-    }
-
-    private long preUpdateTime = 0;
-
-    public void updateFSDiffStats(String name, double diffValue) {
-        if (null == apmInstance || isFSEnd) {
-            return;
-        }
-        updateDiffStats(name, diffValue);
-    }
-
-    public void recordPerformanceDetailData(){
-        if (mHasRecordDetailData){
-            return;
-        }
-        mHasRecordDetailData = true;
-        addStats(KEY_PAGE_STATS_VIEW_CREATE_COST,interactionViewCreateTime);
-        addStats(KEY_PAGE_STATS_COMPONENT_CREATE_COST,interactionComponentCreateTime);
-        addStats(KEY_PAGE_STATS_EXECUTE_JS_CALLBACK_COST,interactionJsCallBackTime);
-        addStats(KEY_PAGE_STATS_LAYOUT_TIME,interactionLayoutTime);
-    }
-
-    public void updateDiffStats(String name, double diffValue) {
-        if (null == apmInstance) {
-            return;
-        }
-        Double preVal = recordStatsMap.containsKey(name) ? recordStatsMap.get(name) : 0;
-        //fix by use ConcurrentHashMap,but not sure,so report if error still happen
-        if (null == preVal){
-            WXExceptionUtils.commitCriticalExceptionRT(
-                "",
-                WXErrorCode.WX_ERR_HASH_MAP_TMP,
-                "updateDiffStats",
-                "key : "+name,
-                null
-            );
-            return;
-        }
-
-        double currentValue = preVal + diffValue;
-        addStats(name, currentValue);
-    }
-
-    public void updateMaxStats(String name, double currentVal) {
-        if (null == apmInstance) {
-            return;
-        }
-        Double maxValue = recordStatsMap.containsKey(name) ? recordStatsMap.get(name) : 0;
-        //fix by use ConcurrentHashMap,but not sure,so report if error still happen
-        if (null == maxValue){
-            WXExceptionUtils.commitCriticalExceptionRT(
-                "",
-                WXErrorCode.WX_ERR_HASH_MAP_TMP,
-                "updateMaxStats",
-                "key : "+name,
-                null
-            );
-            return;
-        }
-        if (maxValue < currentVal) {
-            maxValue = currentVal;
-            addStats(name, maxValue);
-        }
-    }
-
-    public void updateRecordInfo(Map<String, Object> extParams) {
-        if (null == apmInstance || null == extParams) {
-            return;
-        }
-
-        addPropeyFromExtParms(KEY_PAGE_PROPERTIES_REQUEST_TYPE, KEY_PAGE_PROPERTIES_REQUEST_TYPE, extParams);
-        addPropeyFromExtParms("cacheType", KEY_PAGE_PROPERTIES_CACHE_TYPE, extParams);
-        addPropeyFromExtParms("zCacheInfo", KEY_PAGE_PROPERTIES_CACHE_INFO, extParams);
-
-        addStats(KEY_PAGE_STATS_JSLIB_INIT_TIME, WXEnvironment.sJSLibInitTime);
-        addProperty(KEY_PAGE_PROPERTIES_JS_FM_INI, WXEnvironment.JsFrameworkInit);
-
-        Object wxNetLibDownBundleTime = extParams.get("actualNetworkTime");
-        if (wxNetLibDownBundleTime instanceof Long) {
-            updateDiffStats(KEY_PAGE_STATS_ACTUAL_DOWNLOAD_TIME, ((Long)wxNetLibDownBundleTime).doubleValue());
-        }
-    }
-
-    private void addPropeyFromExtParms(String fromKey, String toKey, Map<String, Object> extParams) {
-        Object value = extParams.get(fromKey);
-        if (value instanceof String) {
-            addProperty(toKey, value);
-        }
-    }
-
-    /************** called by IWXHttpAdapter implementer *****************/
-
-    public void actionNetRequest() {
-        if (!isFSEnd) {
-            updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_REQUEST_NUM, 1);
-        }
-        updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_NET_NUM, 1);
-    }
-
-    public void actionNetResult(boolean succeed, String errorCode) {
-        if (succeed) {
-            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_NET_SUCCESS_NUM, 1);
-        } else {
-            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_NET_FAIL_NUM, 1);
-        }
-    }
-
-    /************** called by IWXImgLoaderAdapter implementer *****************/
-
-    public void actionLoadImg() {
-        updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_LOAD_NUM, 1);
-    }
-
-    public void actionLoadImgResult(boolean succeed, String errorCode) {
-        if (succeed) {
-            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_LOAD_SUCCESS_NUM, 1);
-        } else {
-            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_LOAD_FAIL_NUM, 1);
-        }
-    }
-
-    public void sendPerformanceToJS() {
-        if (hasSendInteractionToJS) {
-            return;
-        }
-        hasSendInteractionToJS = true;
-        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(mInstanceId);
-        if (null == instance) {
-            return;
-        }
-
-        Map<String,String> sendProperties = new HashMap<>(2);
-        sendProperties.put(KEY_PAGE_PROPERTIES_BIZ_ID,reportPageName);
-        sendProperties.put(KEY_PAGE_PROPERTIES_BUBDLE_URL,instance.getBundleUrl());
-
-        Map<String,Long> sendStage = new HashMap<>(1);
-        sendStage.put(KEY_PAGE_STAGES_INTERACTION,instance.getWXPerformance().interactionRealUnixTime);
-
-        Map<String, Object> data = new HashMap<>(2);
-        data.put("stage",sendStage);
-        data.put("properties",sendProperties);
-
-        instance.fireGlobalEventCallback("wx_apm", data);
-    }
-
-
-    public String toPerfString() {
-        Long start = stageMap.get(KEY_PAGE_STAGES_RENDER_ORGIGIN);
-        Long end = stageMap.get(KEY_PAGE_STAGES_INTERACTION);
-        Long wxNewFsRender = stageMap.get(KEY_PAGE_STAGES_NEW_FSRENDER);
-        StringBuilder builder = new StringBuilder();
-        if(start != null && end != null){
-            builder.append("interactiveTime " + (end - start) + "ms");
-        }
-        if(wxNewFsRender != null){
-            builder.append(" wxNewFsRender " + (wxNewFsRender) + "ms");
-        }
-        return builder.toString();
-   }
-
-   public void updateNativePerformanceData(Map<String,String> nativePerformanceData){
-        if (null == nativePerformanceData){
-            return;
-        }
-        for (Map.Entry<String,String> entry : nativePerformanceData.entrySet()){
-            double value = -1;
-            try {
-                value = Double.valueOf(entry.getValue());
-            }catch (Exception e){
-                e.printStackTrace();
-            }
-            if (value != -1){
-                recordStatsMap.put(entry.getKey(),value);
-            }
-        }
-   }
- }
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/WXStateRecord.java b/android/sdk/src/main/java/com/taobao/weex/performance/WXStateRecord.java
deleted file mode 100644
index 0711af2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/performance/WXStateRecord.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.performance;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import android.support.annotation.NonNull;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.ui.IFComponentHolder;
-import com.taobao.weex.utils.WXUtils;
-
-/**
- * @author zhongcang
- * @date 2019/6/19
- */
-public class WXStateRecord {
-
-    private RecordList<Info> mExceptionHistory;
-    private RecordList<Info> mActionHistory;
-    private RecordList<Info> mJsfmInitHistory;
-    private RecordList<Info> mJscCrashHistory;
-    private RecordList<Info> mJscReloadHistory;
-    private RecordList<Info> mJsThradWatchHistory;
-    private RecordList<Info> mIPCExceptionHistory;
-
-    private static class SingleTonHolder {
-        private static final WXStateRecord S_INSTANCE = new WXStateRecord();
-    }
-
-    public static WXStateRecord getInstance() {
-        return SingleTonHolder.S_INSTANCE;
-    }
-
-    private WXStateRecord() {
-        mExceptionHistory = new RecordList<>(10);
-        mActionHistory = new RecordList<>(20);
-        mJsfmInitHistory = new RecordList<>(10);
-        mJscCrashHistory = new RecordList<>(10);
-        mJscReloadHistory = new RecordList<>(10);
-        mJsThradWatchHistory = new RecordList<>(20);
-        mIPCExceptionHistory = new RecordList<>(20);
-    }
-
-    /**
-     * check history exception (may be cause ws)
-     */
-    public void recordException(String instanceId, String exception) {
-        String shortException = exception.length() > 200 ?exception.substring(0,200) : exception;
-        recordCommon(mExceptionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, shortException));
-    }
-
-    /**
-     * check history action (may be occupy cpu by preInstance or some task)
-     */
-    public void recordAction(String instanceId, String action) {
-        recordCommon(mActionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, action));
-    }
-
-    public void recordIPCException (String instanceId,String exception){
-        String shortException = exception.length() > 200 ?exception.substring(0,200) : exception;
-        recordCommon(mIPCExceptionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, shortException));
-    }
-
-    /**
-     * check onJSFMInit time,and we know when jsfm is init sucess in reloadJsEngine case
-     */
-    public void onJSFMInit() {
-        recoreJsfmInitHistory("setJsfmVersion");
-    }
-
-    public void recoreJsfmInitHistory(String msg){
-        recordCommon(mJsfmInitHistory,new Info(WXUtils.getFixUnixTime(), "JSFM", msg));
-    }
-
-    public void recordJsThreadWatch(String msg){
-        recordCommon(mJsThradWatchHistory,new Info(WXUtils.getFixUnixTime(), "jsWatch", msg));
-    }
-
-    /**
-     * check onJSEngineReload time,and we know how many times reload and each reload time
-     */
-    public void onJSEngineReload(String instanceId) {
-        recordCommon(mJscReloadHistory,new Info(WXUtils.getFixUnixTime(), instanceId, "onJSEngineReload"));
-    }
-
-    /**
-     * check jsc crash time,and we know how many times jscCrash and each crash time
-     */
-    public void onJSCCrash(String instanceId) {
-        recordCommon(mJscCrashHistory,new Info(WXUtils.getFixUnixTime(), instanceId, "onJSCCrash"));
-    }
-
-    private void recordCommon(RecordList<Info> list ,Info info){
-        if (null == list || null == info){
-            return;
-        }
-        try {
-            list.add(info);
-            if (!list.isEmpty() && list.size()>list.maxSize){
-                list.poll();
-            }
-        }catch (Throwable e){
-            e.getStackTrace();
-        }
-    }
-
-    public Map<String, String> getStateInfo() {
-        Map<String, String> stateInfo = new HashMap<>(5);
-        stateInfo.put("reInitCount", String.valueOf(WXBridgeManager.reInitCount));
-
-        int size = mExceptionHistory.size()+mActionHistory.size()+mJsfmInitHistory.size()
-            +mJscCrashHistory.size()+mJscReloadHistory.size()+mJsThradWatchHistory.size();
-
-        List<Info> reportTimeLineInfo = new ArrayList<>(size);
-        reportTimeLineInfo.addAll(mExceptionHistory);
-        reportTimeLineInfo.addAll(mActionHistory);
-        reportTimeLineInfo.addAll(mJsfmInitHistory);
-        reportTimeLineInfo.addAll(mJscCrashHistory);
-        reportTimeLineInfo.addAll(mJscReloadHistory);
-        reportTimeLineInfo.addAll(mJsThradWatchHistory);
-        reportTimeLineInfo.addAll(mIPCExceptionHistory);
-        Collections.sort(reportTimeLineInfo);
-        stateInfo.put("stateInfoList",reportTimeLineInfo.toString());
-
-        IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
-        if (null != adapter && "true".equalsIgnoreCase(adapter.getConfig("wxapm","dumpIpcPageInfo","true"))){
-            stateInfo.put("pageQueueInfo",WXBridgeManager.getInstance().dumpIpcPageInfo());
-        }
-        return stateInfo;
-    }
-
-    private static class RecordList<E> extends ConcurrentLinkedQueue<E> {
-        private int maxSize;
-
-        public RecordList(int maxSize) {
-            super();
-            this.maxSize = maxSize;
-        }
-    }
-
-    private static class Info implements Comparable<Info>{
-        private long time;
-        private String instanceId;
-        private String msg;
-
-        public Info(long time, String instance, String msg) {
-            this.time = time;
-            this.instanceId = instance;
-            this.msg = msg;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                .append('[').append(instanceId).append(',').append(time).append(',').append(msg).append("]->")
-                .toString();
-        }
-
-        @Override
-        public int compareTo(@NonNull Info next) {
-            if (this.time == next.time){
-                return 0;
-            }
-            return this.time > next.time? 1:-1;
-        }
-    }
-
-    public void startJSThreadWatchDog(){
-        WXBridgeManager.getInstance().post(jsThreadWatchTask);
-    }
-
-    private  long jsThreadTime =-1;
-
-    private Runnable jsThreadWatchTask = new Runnable() {
-        @Override
-        public void run() {
-            if (jsThreadTime == -1){
-                jsThreadTime = WXUtils.getFixUnixTime();
-            }
-            long diff = WXUtils.getFixUnixTime() - jsThreadTime;
-            recordJsThreadWatch("diff:"+diff);
-            jsThreadTime = WXUtils.getFixUnixTime();
-            WXBridgeManager.getInstance().postDelay(jsThreadWatchTask,500);
-        }
-    };
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/WhiteScreenUtils.java b/android/sdk/src/main/java/com/taobao/weex/performance/WhiteScreenUtils.java
deleted file mode 100644
index 6e7543e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/performance/WhiteScreenUtils.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.performance;
-
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.ui.IFComponentHolder;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.WXViewUtils;
-import org.json.JSONObject;
-
-/**
- * @author zhongcang
- * @date 2019/5/30
- */
-public class WhiteScreenUtils {
-
-    public static boolean doWhiteScreenCheck() {
-        IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
-        if (null == configAdapter) {
-            return false;
-        }
-        double randomValue = Math.random() * 100;
-        double max = 100;
-        try {
-            String configValue = configAdapter.getConfig("wxapm", "new_ws_sampling", "100");
-            max = Double.valueOf(configValue);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return randomValue < max;
-    }
-
-    public static boolean isWhiteScreen(WXSDKInstance instance) {
-        if (null == instance) {
-            return false;
-        }
-        View v = instance.getContainerView();
-        if (!(v instanceof ViewGroup)) {
-            return false;
-        }
-
-        if (!WXViewUtils.isViewVisible(v) || !checkParentVisible(v.getParent())){
-            return false;
-        }
-        if (isInWhiteList(instance)){
-            return false;
-        }
-        return !hasLeafViewOrSizeIgnore(v,3);
-    }
-
-    private static boolean isInWhiteList(WXSDKInstance instance){
-        IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
-        if (null == configAdapter){
-            return false;
-        }
-        String whiteList = configAdapter.getConfig("wxapm","ws_white_list",null);
-        if (TextUtils.isEmpty(whiteList)){
-            return false;
-        }
-        try {
-            String[] urlList = whiteList.split(";");
-            for (String whiteUrl : urlList){
-                if (instance.getBundleUrl() != null && instance.getBundleUrl().contains(whiteUrl)){
-                    return true;
-                }
-            }
-        }catch (Exception e){
-            e.printStackTrace();
-        }
-
-        return false;
-    }
-
-    private static boolean checkParentVisible(ViewParent parent){
-        //root view getParent is null
-        if (!(parent instanceof View)){
-            return true;
-        }
-        View vp = (View)parent;
-        boolean visible = vp.getVisibility() == View.VISIBLE && vp.getAlpha()>0;
-        if (!visible){
-            return false;
-        }
-        return checkParentVisible(vp.getParent());
-    }
-
-    private static boolean hasLeafViewOrSizeIgnore(View v,int checkDeep) {
-
-        if (!(v instanceof ViewGroup)) {
-            return true;
-        }
-
-        if (checkDeep > 0){
-            if ( v.getHeight() < 10 || v.getWidth() < 10) {
-                return true;
-            }
-            checkDeep--;
-        }
-
-        ViewGroup group = (ViewGroup)v;
-        for (int i = 0; i < group.getChildCount(); i++) {
-            View child = group.getChildAt(i);
-            boolean res = hasLeafViewOrSizeIgnore(child,checkDeep);
-            if (res) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * get instance viewTree && component tree msg
-     */
-    public static String takeViewTreeSnapShot(WXSDKInstance instance) {
-        if (null == instance) {
-            return "nullInstance";
-        }
-        View v = instance.getContainerView();
-        JSONObject root = geViewDetailTreeMsg(v);
-        if (null != root) {
-            return root.toString();
-        }
-        return "";
-    }
-
-    private static JSONObject geViewDetailTreeMsg(View view) {
-        if (null == view) {
-            return null;
-        }
-        JSONObject node = new JSONObject();
-        try {
-            node.put("width", view.getWidth());
-            node.put("height", view.getHeight());
-            int[] location = new int[2];
-            location[0] = -1;
-            location[1] = -1;
-            view.getLocationOnScreen(location);
-            node.put("x", location[0]);
-            node.put("y", location[1]);
-
-            if (view instanceof ViewGroup) {
-                node.put("type", view.getClass().getSimpleName());
-                ViewGroup group = (ViewGroup)view;
-                for (int i = 0; i < group.getChildCount(); i++) {
-                    node.put("child_"+i, geViewDetailTreeMsg(group.getChildAt(i)));
-                }
-            } else {
-                node.put("type", view.getClass().getSimpleName());
-            }
-
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return node;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/render/WXAbstractRenderContainer.java b/android/sdk/src/main/java/com/taobao/weex/render/WXAbstractRenderContainer.java
deleted file mode 100644
index ade7339..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/render/WXAbstractRenderContainer.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.render;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-import com.taobao.weex.WXSDKInstance;
-import java.lang.ref.WeakReference;
-
-public class WXAbstractRenderContainer extends FrameLayout {
-
-    protected  WeakReference<WXSDKInstance> mSDKInstance;
-    protected boolean mHasConsumeEvent = false;
-
-    public WXAbstractRenderContainer(@NonNull Context context) {
-        super(context);
-    }
-
-    public WXAbstractRenderContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public WXAbstractRenderContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    public WXAbstractRenderContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    public void setSDKInstance(WXSDKInstance instance) {
-        mSDKInstance = new WeakReference<>(instance);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        WXSDKInstance instance;
-        if (mSDKInstance != null && (instance = mSDKInstance.get()) != null) {
-            //re-render instance
-            instance.setSize(w, h);
-        }
-    }
-
-
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        mHasConsumeEvent = true;
-        return super.dispatchTouchEvent(ev);
-    }
-
-    public boolean hasConsumeEvent(){
-        return mHasConsumeEvent;
-    }
-
-    public void createInstanceRenderView(String instanceId){
-
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/tracing/Stopwatch.java b/android/sdk/src/main/java/com/taobao/weex/tracing/Stopwatch.java
deleted file mode 100644
index 10b8be2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/tracing/Stopwatch.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.tracing;
-
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Created by moxun on 2017/6/2.
- */
-
-public class Stopwatch {
-  private static final ThreadLocal<Stopwatch> sThreadLocal = new ThreadLocal<>();
-  private long startNanos;
-  private List<ProcessEvent> splits = new ArrayList<>();
-  private long startMillis;
-
-  private static void prepare() {
-    if (sThreadLocal.get() == null) {
-      sThreadLocal.set(new Stopwatch());
-    }
-  }
-
-  public static void tick() {
-    if (WXTracing.isAvailable()) {
-      try {
-        prepare();
-        if (sThreadLocal.get().startNanos != 0L) {
-          WXLogUtils.w("Stopwatch", "Stopwatch is not reset");
-        }
-        sThreadLocal.get().startNanos = System.nanoTime();
-        sThreadLocal.get().startMillis = System.currentTimeMillis();
-      } catch (Throwable t) {
-        t.printStackTrace();
-      }
-    }
-  }
-
-  public static void split(String fname) {
-    if (WXTracing.isAvailable()) {
-      try {
-        ProcessEvent event = new ProcessEvent();
-        long start = sThreadLocal.get().startMillis;
-        double millis = tackAndTick();
-        event.fname = fname;
-        event.duration = millis;
-        event.startMillis = start;
-        sThreadLocal.get().splits.add(event);
-      } catch (Throwable throwable) {
-        throwable.printStackTrace();
-      }
-    }
-  }
-
-  public static List<ProcessEvent> getProcessEvents() {
-    if (WXTracing.isAvailable()) {
-      tack();
-      List<ProcessEvent> existedEvents = sThreadLocal.get().splits;
-      sThreadLocal.get().splits = new ArrayList<>();
-      return existedEvents;
-    } else {
-      return Collections.emptyList();
-    }
-  }
-
-  public static double tack() {
-    if (WXTracing.isAvailable()) {
-      try {
-        long startNanos = sThreadLocal.get().startNanos;
-        if (startNanos == 0L) {
-          WXLogUtils.w("Stopwatch", "Should call Stopwatch.tick() before Stopwatch.tack() called");
-        }
-        long nanos = System.nanoTime() - startNanos;
-        sThreadLocal.get().startNanos = 0L;
-        return nanosToMillis(nanos);
-      } catch (Throwable throwable) {
-        throwable.printStackTrace();
-      }
-    }
-    return -1;
-  }
-
-  public static long lastTickStamp() {
-    if (WXTracing.isAvailable()) {
-      try {
-        return sThreadLocal.get().startMillis;
-      } catch (Throwable t) {
-        t.printStackTrace();
-      }
-    }
-    return -1;
-  }
-
-  public static double tackAndTick() {
-    double ms = tack();
-    tick();
-    return ms;
-  }
-
-  public static double nanosToMillis(long nanos) {
-    return nanos / 1000000.0;
-  }
-
-  public static double millisUntilNow(long startNanos) {
-    return nanosToMillis(System.nanoTime() - startNanos);
-  }
-
-  public static class ProcessEvent {
-    public String fname;
-    public double duration;
-    public long startMillis;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/tracing/WXTracing.java b/android/sdk/src/main/java/com/taobao/weex/tracing/WXTracing.java
deleted file mode 100644
index 0dc11ce..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/tracing/WXTracing.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.tracing;
-
-import android.os.Looper;
-import android.util.SparseArray;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.ITracingAdapter;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Created by moxun on 2017/6/6.
- */
-
-public class WXTracing {
-  private static final AtomicInteger sIdGenerator = new AtomicInteger(0);
-
-  public static int nextId() {
-    return sIdGenerator.getAndIncrement();
-  }
-
-  public static boolean isAvailable() {
-    return WXEnvironment.isApkDebugable();
-  }
-
-  public static synchronized void submit(TraceEvent event) {
-    ITracingAdapter tracingAdapter = WXSDKManager.getInstance().getTracingAdapter();
-    if (tracingAdapter != null) {
-      tracingAdapter.submitTracingEvent(event);
-    }
-  }
-
-  public static class TraceEvent {
-    public String fname;
-    public String tname;
-    public String ph;
-    public int traceId;
-    public long ts;
-    public String iid;
-    public String ref;
-    public String parentRef;
-    public String name;
-    public String classname;
-    public int parentId = -1;
-    public double duration;
-
-    /**
-     * Internal use
-     */
-    public SparseArray<TraceEvent> subEvents;
-    public String payload;
-    public double parseJsonTime;
-    public boolean isSegment;
-    public Map<String, Object> extParams;
-    public boolean firstScreenFinish;
-
-    private boolean submitted;
-
-    public TraceEvent() {
-      ts = System.currentTimeMillis();
-      traceId = nextId();
-      tname = currentThreadName();
-    }
-
-    public void submit() {
-      if (!submitted) {
-        submitted = true;
-        WXTracing.submit(this);
-      } else {
-        WXLogUtils.w("WXTracing", "Event " + traceId + " has been submitted.");
-      }
-    }
-  }
-
-  public static String currentThreadName() {
-    Thread thread = Thread.currentThread();
-    String name = thread.getName();
-
-    if ("WeexJSBridgeThread".equals(name)) {
-      return "JSThread";
-    } else if ("WeeXDomThread".equals(name)) {
-      return "DOMThread";
-    } else if (Looper.getMainLooper() == Looper.myLooper()) {
-      return "UIThread";
-    }
-
-    return name;
-  }
-
-  public static TraceEvent newEvent(String fname, String instanceId, int parentId) {
-    WXTracing.TraceEvent traceEvent = new TraceEvent();
-    traceEvent.fname = fname;
-    traceEvent.iid = instanceId;
-    traceEvent.traceId = WXTracing.nextId();
-    traceEvent.parentId = parentId;
-    return traceEvent;
-  }
-
-  public static class TraceInfo {
-    public int rootEventId;
-    public long domQueueTime;
-    public long uiQueueTime;
-    public long domThreadStart = -1;
-    public long domThreadNanos;
-    public long uiThreadStart = -1;
-    public long uiThreadNanos;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/ComponentCreator.java b/android/sdk/src/main/java/com/taobao/weex/ui/ComponentCreator.java
deleted file mode 100644
index c2e7f15..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/ComponentCreator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Created by sospartan on 7/27/16.
- */
-public interface ComponentCreator {
-  WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/ExternalLoaderComponentHolder.java b/android/sdk/src/main/java/com/taobao/weex/ui/ExternalLoaderComponentHolder.java
deleted file mode 100644
index b33445c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/ExternalLoaderComponentHolder.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import android.util.Pair;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Created by sospartan on 8/26/16.
- */
-public class ExternalLoaderComponentHolder implements IFComponentHolder {
-  public static final String TAG = "SimpleComponentHolder";
-  private Map<String, Invoker> mPropertyInvokers;
-  private Map<String, Invoker> mMethodInvokers;
-  private final IExternalComponentGetter mClzGetter;
-  private final String mType;
-  private Class mClass;
-
-
-  public ExternalLoaderComponentHolder(String type,IExternalComponentGetter clzGetter) {
-    this.mClzGetter = clzGetter;
-    mType = type;
-  }
-
-  @Override
-  public void loadIfNonLazy() {
-  }
-
-  private synchronized boolean generate(){
-    if(mClass==null){
-      return false;
-    }
-
-    Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = SimpleComponentHolder.getMethods(mClass);
-    mPropertyInvokers = methodPair.first;
-    mMethodInvokers = methodPair.second;
-    return true;
-  }
-
-  @Override
-  public synchronized WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-    if (mClass == null) {
-      mClass = mClzGetter.getExternalComponentClass(mType, instance);
-    }
-    ComponentCreator creator = new SimpleComponentHolder.ClazzComponentCreator(mClass);
-    WXComponent component = creator.createInstance(instance, parent, basicComponentData);
-
-    component.bindHolder(this);
-    return component;
-  }
-
-  @Override
-  public synchronized Invoker getPropertyInvoker(String name){
-    if (mPropertyInvokers == null && !generate()) {
-      return null;
-    }
-
-    return mPropertyInvokers.get(name);
-  }
-
-  @Override
-  public Invoker getMethodInvoker(String name) {
-    if(mMethodInvokers == null && !generate()){
-      return null;
-    }
-    return mMethodInvokers.get(name);
-  }
-
-  @Override
-  public synchronized String[] getMethods() {
-    if(mMethodInvokers == null && !generate()){
-      //generate failed
-      return new String[0];
-    }
-    Set<String> keys = mMethodInvokers.keySet();
-    return keys.toArray(new String[keys.size()]);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/IExternalComponentGetter.java b/android/sdk/src/main/java/com/taobao/weex/ui/IExternalComponentGetter.java
deleted file mode 100644
index 63aaf5c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/IExternalComponentGetter.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by zhengshihan on 16/8/25.
- */
-public interface IExternalComponentGetter {
-    Class<? extends WXComponent> getExternalComponentClass(String type, WXSDKInstance instance);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/IExternalModuleGetter.java b/android/sdk/src/main/java/com/taobao/weex/ui/IExternalModuleGetter.java
deleted file mode 100644
index 80f0257..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/IExternalModuleGetter.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import android.content.Context;
-
-import com.taobao.weex.common.WXModule;
-
-/**
- * Created by zhengshihan on 16/8/25.
- */
-public interface IExternalModuleGetter {
-    Class<? extends WXModule> getExternalModuleClass(String type, Context context);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/IFComponentHolder.java b/android/sdk/src/main/java/com/taobao/weex/ui/IFComponentHolder.java
deleted file mode 100644
index 45344d4..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/IFComponentHolder.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.bridge.JavascriptInvokable;
-
-/**
- * Created by sospartan on 6/23/16.
- */
-public interface IFComponentHolder extends ComponentCreator,JavascriptInvokable {
-
-    /** Prepare component if not a lazy load componnet.**/
-    void loadIfNonLazy();
-
-    Invoker getPropertyInvoker(String name);
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/RenderContextImpl.java b/android/sdk/src/main/java/com/taobao/weex/ui/RenderContextImpl.java
deleted file mode 100644
index 852becf..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/RenderContextImpl.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.dom.RenderContext;
-import com.taobao.weex.ui.component.WXComponent;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Class for rendering view. Method in this class should be run in main thread.
- * This class is also <strong>not</storng> thread safe.
- */
-class RenderContextImpl implements RenderContext {
-
-  private Map<String, WXComponent> mRegistry;
-  private WXSDKInstance mWXSDKInstance;
-
-  public RenderContextImpl(WXSDKInstance instance) {
-    mWXSDKInstance = instance;
-    mRegistry = new ConcurrentHashMap<>();
-  }
-
-  public void destroy() {
-    mWXSDKInstance = null;
-    try {
-      mRegistry.clear();
-    } catch (Throwable e) {
-      e.printStackTrace();
-    }
-  }
-
-  public WXSDKInstance getWXSDKInstance() {
-    return mWXSDKInstance;
-  }
-
-  @Override
-  public WXSDKInstance getInstance() {
-    return mWXSDKInstance;
-  }
-
-  @Override
-  public WXComponent getComponent(String ref) {
-    return mRegistry.get(ref);
-  }
-
-  public void registerComponent(String ref, WXComponent comp) {
-    mRegistry.put(ref, comp);
-  }
-
-  @Override
-  public WXComponent unregisterComponent(String ref) {
-    return mRegistry.remove(ref);
-  }
-
-  public int getComponentCount(){
-    return mRegistry.size();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/SimpleComponentHolder.java b/android/sdk/src/main/java/com/taobao/weex/ui/SimpleComponentHolder.java
deleted file mode 100644
index afd992a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/SimpleComponentHolder.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import android.util.Pair;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.bridge.MethodInvoker;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXComponentProp;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import static com.taobao.weex.bridge.WXBridgeManager.METHOD_REGISTER_COMPONENTS;
-
-/**
- * Created by sospartan on 6/12/16.
- */
-public class SimpleComponentHolder implements IFComponentHolder{
-  public static final String TAG = "SimpleComponentHolder";
-  private final Class<? extends WXComponent> mClz;
-  private Map<String, Invoker> mPropertyInvokers;
-  private Map<String, Invoker> mMethodInvokers;
-  private ComponentCreator mCreator;
-
-  public static class ClazzComponentCreator implements ComponentCreator{
-
-    private Constructor<? extends WXComponent> mConstructor;
-    private final Class<? extends WXComponent> mCompClz;
-
-    public ClazzComponentCreator(Class<? extends WXComponent> c){
-      mCompClz = c;
-    }
-
-    private void loadConstructor() {
-      Class<? extends WXComponent> c = mCompClz;
-      Constructor<? extends WXComponent> constructor;
-      try {
-        constructor = c.getConstructor(WXSDKInstance.class, WXVContainer.class, BasicComponentData.class);
-      } catch (NoSuchMethodException e) {
-        WXLogUtils.d("ClazzComponentCreator", "Use deprecated component constructor");
-        try {
-          //compatible deprecated constructor with 4 args
-          constructor = c.getConstructor(WXSDKInstance.class, WXVContainer.class, boolean.class, BasicComponentData.class);
-        } catch (NoSuchMethodException e1) {
-          try {
-            //compatible deprecated constructor with 5 args
-            constructor = c.getConstructor(WXSDKInstance.class, WXVContainer.class, String.class, boolean.class, BasicComponentData.class);
-          } catch (NoSuchMethodException e2) {
-            throw new WXRuntimeException("Can't find constructor of component.");
-          }
-        }
-      }
-      mConstructor = constructor;
-    }
-
-    @Override
-    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      if(mConstructor == null){
-        loadConstructor();
-      }
-      int parameters = mConstructor.getParameterTypes().length;
-      WXComponent component;
-
-      if(parameters == 3){
-        component =  mConstructor.newInstance(instance,parent, basicComponentData);
-      }else if(parameters == 4){
-        component =  mConstructor.newInstance(instance,parent,false, basicComponentData);
-      }else{
-        //compatible deprecated constructor
-        component =  mConstructor.newInstance(instance,parent,instance.getInstanceId(),parent.isLazy());
-      }
-      return component;
-    }
-  }
-
-  public SimpleComponentHolder(Class<? extends WXComponent> clz) {
-    this(clz,new ClazzComponentCreator(clz));
-  }
-
-  public SimpleComponentHolder(Class<? extends WXComponent> clz,ComponentCreator customCreator) {
-    this.mClz = clz;
-    this.mCreator = customCreator;
-  }
-
-  @Override
-  public void loadIfNonLazy() {
-    Annotation[] annotations = mClz.getDeclaredAnnotations();
-    for (Annotation annotation :
-      annotations) {
-      if (annotation instanceof Component){
-        if(!((Component) annotation).lazyload() && mMethodInvokers == null){
-          generate();
-        }
-        return;
-      }
-    }
-  }
-
-  private synchronized void generate(){
-    if(WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d(TAG, "Generate Component:" + mClz.getSimpleName());
-    }
-
-    Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = getMethods(mClz);
-    mPropertyInvokers = methodPair.first;
-    mMethodInvokers = methodPair.second;
-  }
-
-  public static Pair<Map<String,Invoker>,Map<String,Invoker>> getMethods(Class clz){
-    Map<String, Invoker> methods = new HashMap<>();
-    Map<String, Invoker> mInvokers = new HashMap<>();
-
-    Annotation[] annotations;
-    Annotation anno;
-    try {
-      for (Method method : clz.getMethods()) {
-        try {
-          annotations = method.getDeclaredAnnotations();
-          for (int i = 0, annotationsCount = annotations.length;
-               i < annotationsCount; ++i) {
-            anno = annotations[i];
-            if(anno == null){
-              continue;
-            }
-            if (anno instanceof WXComponentProp) {
-              String name = ((WXComponentProp) anno).name();
-              methods.put(name, new MethodInvoker(method,true));
-              break;
-            }else if(anno instanceof JSMethod){
-              JSMethod methodAnno = (JSMethod)anno;
-              String name = methodAnno.alias();
-              if(JSMethod.NOT_SET.equals(name)){
-                name = method.getName();
-              }
-              mInvokers.put(name, new MethodInvoker(method,methodAnno.uiThread()));
-              break;
-            }
-          }
-        } catch (ArrayIndexOutOfBoundsException | IncompatibleClassChangeError e) {
-          //ignore: getDeclaredAnnotations may throw this
-        }
-      }
-    }catch (IndexOutOfBoundsException e){
-      e.printStackTrace();
-      //ignore: getMethods may throw this
-    }catch (Exception e){ // in meizhu mobile, throw class not found exception in getMethods
-      WXLogUtils.e(TAG, e);
-    }
-    return new Pair<>(methods,mInvokers);
-  }
-
-
-
-  @Override
-  public synchronized WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-    WXComponent component = mCreator.createInstance(instance, parent, basicComponentData);
-
-    component.bindHolder(this);
-    return component;
-  }
-
-  @Override
-  public synchronized Invoker getPropertyInvoker(String name){
-      if (mPropertyInvokers == null) {
-        generate();
-      }
-
-    return mPropertyInvokers.get(name);
-  }
-
-  @Override
-  public Invoker getMethodInvoker(String name) {
-    if(mMethodInvokers == null){
-      generate();
-    }
-    return mMethodInvokers.get(name);
-  }
-
-  @Override
-  public synchronized String[] getMethods() {
-    if(mMethodInvokers == null){
-      generate();
-    }
-    Set<String> keys = mMethodInvokers.keySet();
-    try {
-      return keys.toArray(new String[keys.size()]);
-    } catch (Throwable throwable) {
-      if(mClz != null) {
-        String name = mClz.getName();
-        String errorMsg = name + ": gen methods failed";
-        WXExceptionUtils.commitCriticalExceptionRT(null,
-                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT,
-                METHOD_REGISTER_COMPONENTS, errorMsg,
-                null);
-      }
-
-      return new String[1];
-    }
-
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/WXComponentRegistry.java b/android/sdk/src/main/java/com/taobao/weex/ui/WXComponentRegistry.java
deleted file mode 100644
index 9aaf6a0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/WXComponentRegistry.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.WXException;
-import com.taobao.weex.ui.config.AutoScanConfigRegister;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.cache.RegisterCache;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * All components must be registered within this class before used.
- */
-public class WXComponentRegistry {
-
-  private static Map<String, IFComponentHolder> sTypeComponentMap = new ConcurrentHashMap<>();
-  private static ArrayList<Map<String, Object>> sComponentInfos=new ArrayList<>();
-
-  public static synchronized boolean registerComponent(Map<String, RegisterCache.ComponentCache> componentCacheMap) {
-    if (componentCacheMap.isEmpty())
-      return true;
-    final Iterator<Map.Entry<String, RegisterCache.ComponentCache>> iterator = componentCacheMap.entrySet().iterator();
-    WXBridgeManager.getInstance().post(new Runnable() {
-      @Override
-      public void run() {
-        ArrayList<Map<String, Object>> coms = new ArrayList<>();
-        while (iterator.hasNext()) {
-          Map.Entry<String, RegisterCache.ComponentCache> next = iterator.next();
-          try {
-            RegisterCache.ComponentCache value = next.getValue();
-            Map<String, Object> registerInfo = value.componentInfo;
-            if (registerInfo == null) {
-              registerInfo = new HashMap<>();
-            }
-            registerInfo.put("type", value.type);
-            registerInfo.put("methods", value.holder.getMethods());
-            registerNativeComponent(value.type, value.holder);
-            sComponentInfos.add(registerInfo);
-            coms.add(registerInfo);
-          } catch (WXException e) {
-            e.printStackTrace();
-          }
-        }
-        WXSDKManager.getInstance().registerComponents(coms);
-      }
-    });
-    return true;
-  }
-
-  public static synchronized boolean registerComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) throws WXException {
-    if (holder == null || TextUtils.isEmpty(type)) {
-      return false;
-    }
-
-    if(RegisterCache.getInstance().cacheComponent(type,holder,componentInfo)) {
-      return true;
-    }
-
-    //execute task in js thread to make sure register order is same as the order invoke register method.
-    WXBridgeManager.getInstance()
-        .post(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          Map<String, Object> registerInfo = componentInfo;
-          if (registerInfo == null){
-            registerInfo = new HashMap<>();
-          }
-
-          registerInfo.put("type",type);
-          registerInfo.put("methods",holder.getMethods());
-          registerNativeComponent(type, holder);
-          registerJSComponent(registerInfo);
-          sComponentInfos.add(registerInfo);
-        } catch (WXException e) {
-          WXLogUtils.e("register component error:", e);
-        }
-
-      }
-    });
-    return true;
-  }
-
-  private static boolean registerNativeComponent(String type, IFComponentHolder holder) throws WXException {
-    try {
-      holder.loadIfNonLazy();
-      sTypeComponentMap.put(type, holder);
-    }catch (ArrayStoreException e){
-      e.printStackTrace();
-      //ignore: ArrayStoreException: java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
-    }
-    return true;
-  }
-
-  private static boolean registerJSComponent(Map<String, Object> componentInfo) throws WXException {
-    ArrayList<Map<String, Object>> coms = new ArrayList<>();
-    coms.add(componentInfo);
-    WXSDKManager.getInstance().registerComponents(coms);
-    return true;
-  }
-
-  public static IFComponentHolder getComponent(String type) {
-    return sTypeComponentMap.get(type);
-  }
-
-  public static void reload(){
-    WXBridgeManager.getInstance().post(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          for(Map<String,Object> com:sComponentInfos){
-            registerJSComponent(com);
-          }
-        } catch (WXException e) {
-          WXLogUtils.e("", e);
-        }
-      }
-    });
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderHandler.java b/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderHandler.java
deleted file mode 100644
index 2bfb685..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderHandler.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-class WXRenderHandler extends Handler {
-
-    public WXRenderHandler() {
-        super(Looper.getMainLooper());
-    }
-
-    public final boolean post(String instanceId, Runnable r) {
-        Message msg = Message.obtain(this, r);
-        // Use what to match runnable. Make sure don't override callback method.
-        msg.what = instanceId.hashCode();
-        return sendMessageDelayed(msg, 0);
-    }
-
-    @Override
-    public void handleMessage(Message msg) {
-        super.handleMessage(msg);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java
deleted file mode 100644
index 85f54b7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import android.opengl.GLES10;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.dom.RenderContext;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.ui.action.BasicGraphicAction;
-import com.taobao.weex.ui.action.GraphicActionBatchAction;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-
-
-
-/**
- * Manager class for render operation, mainly for managing {@link RenderContextImpl}.
- * This is <strong>not</strong> a thread-safe class
- */
-public class WXRenderManager {
-
-  private volatile ConcurrentHashMap<String, RenderContextImpl> mRenderContext;
-  private WXRenderHandler mWXRenderHandler;
-  private String mCurrentBatchInstanceId = null;
-  private ArrayList<Map<String,Object>> mBatchActions = new ArrayList<>();
-  private final int MAX_DROP_FRAME_NATIVE_BATCH = 2000;
-  private final static  String sKeyAction = "Action";
-  private static int nativeBatchTimes = 0;
-  private static int mOpenGLRenderLimitValue = 0;
-
-  public WXRenderManager() {
-    mRenderContext = new ConcurrentHashMap<>();
-    mWXRenderHandler = new WXRenderHandler();
-  }
-
-  public RenderContext getRenderContext(String instanceId) {
-    return mRenderContext.get(instanceId);
-  }
-
-  public @Nullable
-  WXComponent getWXComponent(String instanceId, String ref) {
-    if (instanceId == null || TextUtils.isEmpty(ref)) {
-      return null;
-    }
-    RenderContext stmt = getRenderContext(instanceId);
-    return stmt == null ? null : stmt.getComponent(ref);
-  }
-
-  public WXSDKInstance getWXSDKInstance(String instanceId) {
-    RenderContextImpl statement = mRenderContext.get(instanceId);
-    if (statement == null) {
-      return null;
-    }
-    return statement.getWXSDKInstance();
-  }
-
-    public static int getOpenGLRenderLimitValue() {
-      if(mOpenGLRenderLimitValue == 0){
-          int maxsize = 0;
-              try {
-                  EGL10 egl = (EGL10) EGLContext.getEGL();
-                  EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-                  int[] vers = new int[2];
-                  egl.eglInitialize(dpy, vers);
-                  int[] configAttr = {
-                          EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER,
-                          EGL10.EGL_LEVEL, 0,
-                          EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,
-                          EGL10.EGL_NONE};
-                  EGLConfig[] configs = new EGLConfig[1];
-                  int[] numConfig = new int[1];
-                  egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig);
-                  if(numConfig[0] == 0){
-                      //There is something wrong with opengl environment.
-                      maxsize = -1;
-                      egl.eglTerminate(dpy);
-                  }else {
-                      EGLConfig config = configs[0];
-                      int[] surfAttr = {
-                              EGL10.EGL_WIDTH, 64,
-                              EGL10.EGL_HEIGHT, 64,
-                              EGL10.EGL_NONE};
-                      EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr);
-                      final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;// missing in EGL10
-                      int[] ctxAttrib = {
-                              EGL_CONTEXT_CLIENT_VERSION, 1,
-                              EGL10.EGL_NONE};
-                      EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib);
-                      egl.eglMakeCurrent(dpy, surf, surf, ctx);
-                      int[] maxSize = new int[1];
-                      GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
-                      egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,
-                              EGL10.EGL_NO_CONTEXT);
-                      egl.eglDestroySurface(dpy, surf);
-                      egl.eglDestroyContext(dpy, ctx);
-                      egl.eglTerminate(dpy);
-                      maxsize = maxSize[0];
-                  }
-              } catch(Exception e){
-                  WXLogUtils.e(WXLogUtils.getStackTrace(e));
-              }
-          mOpenGLRenderLimitValue = maxsize;
-      }
-      return mOpenGLRenderLimitValue;
-    }
-
-  @RestrictTo(Scope.LIBRARY)
-  public void postOnUiThread(Runnable runnable, long delayMillis) {
-    mWXRenderHandler.postDelayed(WXThread.secure(runnable), delayMillis);
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  public void postOnUiThread(Runnable runnable,final String instanceId){
-    mWXRenderHandler.post(instanceId, WXThread.secure(runnable));
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  public void postOnUiThread(Runnable runnable){
-    mWXRenderHandler.post(WXThread.secure(runnable));
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  public void removeTask(Runnable runnable){
-    mWXRenderHandler.removeCallbacks(runnable);
-  }
-
-  /**
-   * Remove renderStatement, can only be invoked in UI thread.
-   *
-   * @param instanceId {@link WXSDKInstance#mInstanceId}
-   */
-  public void removeRenderStatement(String instanceId) {
-    if (!WXUtils.isUiThread()) {
-      throw new WXRuntimeException("[WXRenderManager] removeRenderStatement can only be called in main thread");
-    }
-    RenderContextImpl statement = mRenderContext.remove(instanceId);
-
-    if (statement != null) {
-      statement.destroy();
-    }
-    if(instanceId == null) {
-      mWXRenderHandler.removeCallbacksAndMessages(null);
-    } else {
-      // use hashCode to match message's what.
-      mWXRenderHandler.removeMessages(instanceId.hashCode());
-    }
-  }
-
-  private void postAllStashedGraphicAction(final String instanceId,final BasicGraphicAction action) {
-      final RenderContextImpl renderContext = mRenderContext.get(instanceId);
-
-      /// keep actions if renderContext still exist
-      ArrayList<Map<String, Object>> tmpList = null;
-      if (renderContext != null) {
-        tmpList = new ArrayList<>(mBatchActions);
-      }
-
-      // clear stashed actions
-      this.mBatchActions.clear();
-      mCurrentBatchInstanceId = null;
-      nativeBatchTimes = 0;
-
-      // return if renderContext has been destroyed
-      if (renderContext == null) {
-        return;
-      }
-
-      /// post actions if renderContext still exist
-      ArrayList<BasicGraphicAction> actions = new ArrayList<>(tmpList.size());
-      for (int i = 0 ; i < tmpList.size(); i ++) {
-          Map<String, Object> item = tmpList.get(i);
-          Object mustBeAction = item.get(sKeyAction);
-          if (!(mustBeAction instanceof BasicGraphicAction)) {
-            continue;
-          }
-          BasicGraphicAction tmpAction = (BasicGraphicAction)mustBeAction;
-          if (tmpAction.mActionType == BasicGraphicAction.ActionTypeBatchBegin || tmpAction.mActionType == BasicGraphicAction.ActionTypeBatchEnd) {
-            continue;
-          }
-          actions.add(tmpAction);
-      }
-      postGraphicAction(instanceId, new GraphicActionBatchAction(action.getWXSDKIntance(),action.getRef(), actions));
-  }
-
-  public void postGraphicAction(final String instanceId, final BasicGraphicAction action) {
-    final RenderContextImpl renderContext = mRenderContext.get(instanceId);
-    if (renderContext == null) {
-      return;
-    }
-
-    // If more than two pages exist and mCurrentBatchInstanceId not matches new instanceId, we will post all stashed actions at once.
-    // That will cause losing efficacy of batch action, but it is acceptable because it's not serious problem.
-    if (mCurrentBatchInstanceId != null && instanceId != null && !mCurrentBatchInstanceId.equals(instanceId) && mBatchActions.size() > 0) {
-      Map<String, Object> lastItem = mBatchActions.get(mBatchActions.size() - 1);
-      Object mustBeAction = lastItem.get(sKeyAction);
-      if (mustBeAction instanceof BasicGraphicAction) {
-        BasicGraphicAction lastAction = (BasicGraphicAction)mustBeAction;
-        postAllStashedGraphicAction(mCurrentBatchInstanceId, lastAction);
-      }
-    }
-
-    if (action.mActionType == BasicGraphicAction.ActionTypeBatchEnd) {
-        postAllStashedGraphicAction(instanceId,action);
-        return;
-    } else if (action.mActionType == BasicGraphicAction.ActionTypeBatchBegin || this.mBatchActions.size() > 0 ) {
-        nativeBatchTimes ++ ;
-        if (nativeBatchTimes > MAX_DROP_FRAME_NATIVE_BATCH) {
-            postAllStashedGraphicAction(instanceId,action);
-        } else {
-            HashMap<String, Object> item = new HashMap<>(1);
-            item.put(sKeyAction, action);
-            mBatchActions.add(item);
-            mCurrentBatchInstanceId = instanceId;
-            return;
-        }
-    }
-
-    mWXRenderHandler.post(instanceId, action);
-  }
-
-  public void registerInstance(WXSDKInstance instance) {
-    if (instance.getInstanceId() == null) {
-      WXExceptionUtils.commitCriticalExceptionRT(null,
-              WXErrorCode.WX_RENDER_ERR_INSTANCE_ID_NULL,
-              "registerInstance",
-              WXErrorCode.WX_RENDER_ERR_INSTANCE_ID_NULL.getErrorMsg() + "instanceId is null",
-              null);
-    } else {
-      mRenderContext.put(instance.getInstanceId(), new RenderContextImpl(instance));
-    }
-  }
-
-  public List<WXSDKInstance> getAllInstances() {
-    ArrayList<WXSDKInstance> instances = null;
-    if (mRenderContext != null && !mRenderContext.isEmpty()) {
-      instances = new ArrayList<WXSDKInstance>();
-      for (Map.Entry<String, RenderContextImpl> entry : mRenderContext.entrySet()) {
-        RenderContextImpl renderStatement = entry.getValue();
-        if (renderStatement != null) {
-          instances.add(renderStatement.getWXSDKInstance());
-        }
-      }
-    }
-    return instances;
-  }
-
-  public void registerComponent(String instanceId, String ref, WXComponent comp) {
-    RenderContextImpl statement = mRenderContext.get(instanceId);
-    if (statement != null) {
-      statement.registerComponent(ref, comp);
-      if (null != statement.getInstance()){
-        statement.getInstance().getApmForInstance().updateMaxStats(
-            WXInstanceApm.KEY_PAGE_STATS_MAX_COMPONENT_NUM,
-            statement.getComponentCount()
-        );
-      }
-    }
-  }
-
-  public WXComponent unregisterComponent(String instanceId, String ref) {
-    RenderContextImpl statement = mRenderContext.get(instanceId);
-    if (statement != null) {
-      if (null != statement.getInstance()){
-        statement.getInstance().getApmForInstance().updateMaxStats(
-            WXInstanceApm.KEY_PAGE_STATS_MAX_COMPONENT_NUM,
-            statement.getComponentCount()
-        );
-      }
-      return statement.unregisterComponent(ref);
-    } else {
-      return null;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionAddRule.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionAddRule.java
deleted file mode 100644
index 5e3febe..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionAddRule.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.font.FontAdapter;
-import com.taobao.weex.utils.FontDO;
-import com.taobao.weex.utils.TypefaceUtil;
-
-/**
- * Created by listen on 18/01/10.
- */
-public class ActionAddRule implements IExecutable {
-
-  private final String mPageId;
-  private final String mType;
-  private final JSONObject mData;
-
-  public ActionAddRule(String pageId, String type, JSONObject data) {
-    this.mPageId = pageId;
-    this.mType = type;
-    this.mData = data;
-  }
-
-  @Override
-  public void executeAction() {
-    WXSDKInstance instance = WXSDKManager.getInstance().getWXRenderManager().getWXSDKInstance(mPageId);
-    if (instance == null || instance.isDestroy()) {
-      return;
-    }
-
-    if (!Constants.Name.FONT_FACE.equals(mType)) {
-      return;
-    }
-
-    FontDO fontDO = parseFontDO(mData, instance);
-    if (fontDO != null && !TextUtils.isEmpty(fontDO.getFontFamilyName())) {
-      notifyAddFontRule(instance, fontDO);
-      FontDO cacheFontDO = TypefaceUtil.getFontDO(fontDO.getFontFamilyName());
-      if (cacheFontDO == null || !TextUtils.equals(cacheFontDO.getUrl(), fontDO.getUrl())) {
-        TypefaceUtil.putFontDO(fontDO);
-        TypefaceUtil.loadTypeface(fontDO, true);
-      } else {
-        TypefaceUtil.loadTypeface(cacheFontDO, true);
-      }
-    }
-
-  }
-
-  private FontDO parseFontDO(JSONObject jsonObject,WXSDKInstance instance) {
-    if(jsonObject == null) {
-      return null;
-    }
-    String src = jsonObject.getString(Constants.Name.SRC);
-    String name = jsonObject.getString(Constants.Name.FONT_FAMILY);
-
-    return new FontDO(name, src,instance);
-  }
-
-
-  private void notifyAddFontRule(WXSDKInstance instance, FontDO fontDO){
-    FontAdapter fontAdapter = WXSDKManager.getInstance().getFontAdapter();
-    if(fontAdapter != null){
-        fontAdapter.onAddFontRule(instance.getInstanceId(), fontDO.getFontFamilyName(), fontDO.getUrl());
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetComponentRect.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetComponentRect.java
deleted file mode 100644
index 78c2875..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetComponentRect.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.view.View;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.SimpleJSCallback;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by listen on 18/01/10.
- */
-public class ActionGetComponentRect extends BasicGraphicAction {
-
-  private final String mCallback;
-
-  public ActionGetComponentRect(WXSDKInstance instance, String ref, String callback) {
-    super(instance, ref);
-    this.mCallback = callback;
-  }
-
-  @Override
-  public void executeAction() {
-    WXSDKInstance instance = getWXSDKIntance();
-    if (instance == null || instance.isDestroy()) {
-      return;
-    }
-
-    JSCallback jsCallback = new SimpleJSCallback(instance.getInstanceId(), mCallback);
-
-    if (TextUtils.isEmpty(getRef())) {
-      Map<String, Object> options = new HashMap<>();
-      options.put("result", false);
-      options.put("errMsg", "Illegal parameter");
-      jsCallback.invoke(options);
-    } else if ("viewport".equalsIgnoreCase(getRef())) {
-      callbackViewport(instance, jsCallback);
-    } else {
-      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-      if (component == null) {
-        return;
-      }
-
-      Map<String, Object> options = new HashMap<>();
-      if (component != null) {
-        int viewPort = instance.getInstanceViewPortWidth();
-        Map<String, Float> size = new HashMap<>();
-        Rect sizes = component.getComponentSize();
-        size.put("width", getWebPxValue(sizes.width(),viewPort));
-        size.put("height", getWebPxValue(sizes.height(),viewPort));
-        size.put("bottom", getWebPxValue(sizes.bottom,viewPort));
-        size.put("left", getWebPxValue(sizes.left,viewPort));
-        size.put("right", getWebPxValue(sizes.right,viewPort));
-        size.put("top", getWebPxValue(sizes.top,viewPort));
-        options.put("size", size);
-        options.put("result", true);
-      } else {
-        options.put("errMsg", "Component does not exist");
-      }
-      jsCallback.invoke(options);
-    }
-  }
-
-  private void callbackViewport(WXSDKInstance instance, JSCallback jsCallback) {
-    View container;
-    if ((container = instance.getContainerView()) != null) {
-      Map<String, Object> options = new HashMap<>();
-      Map<String, Float> sizes = new HashMap<>();
-      int[] location = new int[2];
-      instance.getContainerView().getLocationOnScreen(location);
-      int viewport = instance.getInstanceViewPortWidth();
-      sizes.put("left", 0f);
-      sizes.put("top", 0f);
-      sizes.put("right", getWebPxValue(container.getWidth(),viewport));
-      sizes.put("bottom", getWebPxValue(container.getHeight(),viewport));
-      sizes.put("width", getWebPxValue(container.getWidth(),viewport));
-      sizes.put("height", getWebPxValue(container.getHeight(),viewport));
-      options.put("size", sizes);
-      options.put("result", true);
-      jsCallback.invoke(options);
-    } else {
-      Map<String, Object> options = new HashMap<>();
-      options.put("result", false);
-      options.put("errMsg", "Component does not exist");
-      jsCallback.invoke(options);
-    }
-  }
-
-  @NonNull
-  private float getWebPxValue(int value,int viewport) {
-    return WXViewUtils.getWebPxByWidth(value, viewport);
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetLayoutDirection.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetLayoutDirection.java
deleted file mode 100644
index 039bdfc..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetLayoutDirection.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.view.View;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.SimpleJSCallback;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by listen on 18/09/12.
- */
-public class ActionGetLayoutDirection extends BasicGraphicAction {
-
-  private final String mCallback;
-
-  public ActionGetLayoutDirection(WXSDKInstance instance, String ref, String callback) {
-    super(instance, ref);
-    this.mCallback = callback;
-  }
-
-  @Override
-  public void executeAction() {
-    WXSDKInstance instance = getWXSDKIntance();
-    if (instance == null || instance.isDestroy()) {
-      return;
-    }
-
-    JSCallback jsCallback = new SimpleJSCallback(instance.getInstanceId(), mCallback);
-
-    if (TextUtils.isEmpty(getRef())) {
-      Map<String, Object> options = new HashMap<>();
-      options.put("result", false);
-      options.put("errMsg", "Illegal parameter");
-      jsCallback.invoke(options);
-    } else if ("viewport".equalsIgnoreCase(getRef())) {
-      callbackViewport(instance, jsCallback);
-    } else {
-      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-      if (component == null) {
-        return;
-      }
-
-      String directionRet = "ltr";
-      if (component != null) {
-        int direction = NativeRenderObjectUtils.nativeRenderObjectGetLayoutDirectionFromPathNode(component.getRenderObjectPtr());
-        switch (direction) {
-          case 0: {
-            directionRet = "inherit";
-            break;
-          }
-          case 1: {
-            directionRet = "ltr";
-            break;
-          }
-          case 2: {
-            directionRet = "rtl";
-            break;
-          }
-          default: {
-            directionRet = "ltr";
-            break;
-          }
-
-        }
-      }
-      jsCallback.invoke(directionRet);
-    }
-  }
-
-  private void callbackViewport(WXSDKInstance instance, JSCallback jsCallback) {
-    View container;
-    if ((container = instance.getContainerView()) != null) {
-      Map<String, Object> options = new HashMap<>();
-      options.put("direction", "ltr");
-      options.put("result", true);
-      jsCallback.invoke(options);
-    } else {
-      Map<String, Object> options = new HashMap<>();
-      options.put("result", false);
-      options.put("errMsg", "Component does not exist");
-      jsCallback.invoke(options);
-    }
-  }
-
-  @NonNull
-  private float getWebPxValue(int value,int viewport) {
-    return WXViewUtils.getWebPxByWidth(value, viewport);
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionInvokeMethod.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionInvokeMethod.java
deleted file mode 100644
index f078d1b..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionInvokeMethod.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.alibaba.fastjson.JSONArray;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXLogUtils;
-
-/**
- * Created by listen on 18/01/10.
- */
-public class ActionInvokeMethod implements IExecutable {
-
-  private static final String TAG = "ActionInvokeMethod";
-
-  private final String mMethod;
-  private final JSONArray mArgs;
-  private String mPageId;
-  private String mRef;
-
-  public ActionInvokeMethod(String pageId, String ref, String method, JSONArray args) {
-    this.mPageId = pageId;
-    this.mRef = ref;
-    this.mMethod = method;
-    this.mArgs = args;
-  }
-
-  @Override
-  public void executeAction() {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(mPageId, mRef);
-    if(component == null){
-      WXLogUtils.e(TAG,"target component not found.");
-      return;
-    }
-    component.invoke(mMethod,mArgs);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionReloadPage.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionReloadPage.java
deleted file mode 100644
index 42705f6..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionReloadPage.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.util.Log;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-
-/**
- * Created by listen on 18/01/09.
- */
-public class ActionReloadPage implements IExecutable {
-
-  private final String TAG = "ReloadPageAction";
-  private boolean mReloadThis;
-  private String mPageId;
-
-  public ActionReloadPage(String pageId, boolean reloadThis) {
-    this.mPageId = pageId;
-    this.mReloadThis = reloadThis;
-  }
-
-  @Override
-  public void executeAction() {
-    final WXSDKInstance instance = WXSDKManager.getInstance().getWXRenderManager().getWXSDKInstance(mPageId);
-    if (instance != null) {
-      instance.reloadPage(mReloadThis);
-    } else {
-      Log.e(TAG, "ReloadPageAction executeDom reloadPage instance is null");
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/BasicComponentData.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/BasicComponentData.java
deleted file mode 100644
index 9d12450..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/BasicComponentData.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-import android.view.View;
-
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.Map;
-import java.util.Set;
-
-public class BasicComponentData<T extends View> {
-
-  public String mRef;
-  public String mComponentType;
-  public String mParentRef;
-  private WXStyle mStyles;
-  private WXAttr mAttributes;
-  private WXEvent mEvents;
-  private CSSShorthand mMargins;
-  private CSSShorthand mPaddings;
-  private CSSShorthand mBorders;
-  private long renderObjectPr = 0;
-
-  public BasicComponentData(String ref, String componentType, String parentRef) {
-    this.mRef = ref;
-    this.mComponentType = componentType;
-    this.mParentRef = parentRef;
-  }
-
-  public void addStyle(Map<String, Object> styles) {
-    addStyle(styles, false);
-  }
-
-  public final void addStyle(Map<String, Object> styles, boolean byPesudo) {
-    if (styles == null || styles.isEmpty()) {
-      return;
-    }
-    if (mStyles == null) {
-      mStyles = new WXStyle(styles);
-    }
-    else {
-      mStyles.putAll(styles, byPesudo);
-    }
-  }
-
-  public final void addAttr(Map<String, Object> attrs) {
-    if (attrs == null || attrs.isEmpty()) {
-      return;
-    }
-    if (mAttributes == null) {
-      mAttributes = new WXAttr(attrs, 0);
-    }
-    else {
-      mAttributes.putAll(attrs);
-    }
-  }
-
-  public final void addEvent(Set<String> events) {
-    if (events == null || events.isEmpty()) {
-      return;
-    }
-    if (mEvents == null) {
-      mEvents = new WXEvent();
-    }
-    mEvents.addAll(events);
-  }
-
-  public final void addShorthand(float[] shorthand, CSSShorthand.TYPE type) {
-    if (shorthand == null) {
-      shorthand = new float[] {0, 0, 0, 0};
-    }
-    if (shorthand.length == 4) {
-      switch (type) {
-        case MARGIN:
-          if (mMargins == null) {
-            mMargins = new CSSShorthand(shorthand);
-          } else {
-            mMargins.replace(shorthand);
-          }
-          break;
-        case PADDING:
-          if (mPaddings == null) {
-            mPaddings = new CSSShorthand(shorthand);
-          } else {
-            mPaddings.replace(shorthand);
-          }
-          break;
-        case BORDER:
-          if (mBorders == null) {
-            mBorders = new CSSShorthand(shorthand);
-          } else {
-            mBorders.replace(shorthand);
-          }
-          break;
-        default:
-          break;
-      }
-    }
-  }
-
-  public final void addShorthand(Map<String, String> shorthand) {
-    if (shorthand != null && !shorthand.isEmpty()) {
-      for (Map.Entry<String, String> item : shorthand.entrySet()) {
-        String key = item.getKey();
-        switch (key) {
-          case Constants.Name.MARGIN:
-            addMargin(CSSShorthand.EDGE.ALL, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.MARGIN_LEFT:
-            addMargin(CSSShorthand.EDGE.LEFT, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.MARGIN_TOP:
-            addMargin(CSSShorthand.EDGE.TOP, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.MARGIN_RIGHT:
-            addMargin(CSSShorthand.EDGE.RIGHT, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.MARGIN_BOTTOM:
-            addMargin(CSSShorthand.EDGE.BOTTOM,WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.BORDER_WIDTH:
-            addBorder(CSSShorthand.EDGE.ALL, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.BORDER_TOP_WIDTH:
-            addBorder(CSSShorthand.EDGE.TOP, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.BORDER_RIGHT_WIDTH:
-            addBorder(CSSShorthand.EDGE.RIGHT, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.BORDER_BOTTOM_WIDTH:
-            addBorder(CSSShorthand.EDGE.BOTTOM, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.BORDER_LEFT_WIDTH:
-            addBorder(CSSShorthand.EDGE.LEFT, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.PADDING:
-            addPadding(CSSShorthand.EDGE.ALL, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.PADDING_LEFT:
-            addPadding(CSSShorthand.EDGE.LEFT, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.PADDING_TOP:
-            addPadding(CSSShorthand.EDGE.TOP, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.PADDING_RIGHT:
-            addPadding(CSSShorthand.EDGE.RIGHT, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-          case Constants.Name.PADDING_BOTTOM:
-            addPadding(CSSShorthand.EDGE.BOTTOM, WXUtils.fastGetFloat(shorthand.get(key)));
-            break;
-        }
-      }
-    }
-  }
-
-  private void addMargin(CSSShorthand.EDGE spacingType, float margin) {
-    if (mMargins == null) {
-      mMargins = new CSSShorthand();
-    }
-    mMargins.set(spacingType, margin);
-  }
-
-  private void addPadding(CSSShorthand.EDGE spacingType, float padding) {
-    if (mPaddings == null) {
-      mPaddings = new CSSShorthand();
-    }
-    mPaddings.set(spacingType, padding);
-  }
-
-  private void addBorder(CSSShorthand.EDGE spacingType, float border) {
-    if (mBorders == null) {
-      mBorders = new CSSShorthand();
-    }
-    mBorders.set(spacingType, border);
-  }
-
-  public final @NonNull
-  WXStyle getStyles() {
-    if (mStyles == null) {
-      mStyles = new WXStyle();
-    }
-    return mStyles;
-  }
-
-  public final @NonNull
-  WXAttr getAttrs() {
-    if (mAttributes == null) {
-      mAttributes = new WXAttr();
-    }
-    return mAttributes;
-  }
-
-  public final @NonNull
-  WXEvent getEvents() {
-    if (mEvents == null) {
-      mEvents = new WXEvent();
-    }
-    return mEvents;
-  }
-
-  /**
-   * Get this node's margin, as defined by cssstyle + default margin.
-   */
-  public final @NonNull
-  CSSShorthand getMargin() {
-    if (mMargins == null) {
-      mMargins = new CSSShorthand();
-    }
-    return mMargins;
-  }
-
-  /**
-   * Get this node's padding, as defined by cssstyle + default padding.
-   */
-  public final @NonNull
-  CSSShorthand getPadding() {
-    if (mPaddings == null) {
-      mPaddings = new CSSShorthand();
-    }
-    return mPaddings;
-  }
-
-  /**
-   * Get this node's border, as defined by cssstyle.
-   */
-  public @NonNull
-  CSSShorthand getBorder() {
-    if (mBorders == null) {
-      mBorders = new CSSShorthand();
-    }
-    return mBorders;
-  }
-
-  public final void setMargins(@NonNull CSSShorthand mMargins) {
-    this.mMargins = mMargins;
-  }
-
-  public final void setPaddings(@NonNull CSSShorthand mPaddings) {
-    this.mPaddings = mPaddings;
-  }
-
-  public final void setBorders(@NonNull CSSShorthand mBorders) {
-    this.mBorders = mBorders;
-  }
-
-
-
-  @Override
-  public BasicComponentData clone() throws CloneNotSupportedException {
-    BasicComponentData basicComponentData = new BasicComponentData(mRef, mComponentType, mParentRef);
-    basicComponentData.setBorders(getBorder().clone());
-    basicComponentData.setMargins(getMargin().clone());
-    basicComponentData.setPaddings(getPadding().clone());
-    if(mAttributes != null){
-      basicComponentData.mAttributes = mAttributes.clone();
-    }
-    if(mStyles != null){
-      basicComponentData.mStyles = mStyles.clone();
-    }
-    if(mEvents != null){
-      basicComponentData.mEvents = mEvents.clone();
-    }
-
-    if(renderObjectPr != 0){
-      basicComponentData.setRenderObjectPr(NativeRenderObjectUtils.nativeCopyRenderObject(renderObjectPr));
-    }
-    return basicComponentData;
-  }
-
-  public long getRenderObjectPr() {
-    return renderObjectPr;
-  }
-
-  public boolean isRenderPtrEmpty(){
-    return  renderObjectPr == 0;
-  }
-
-  public synchronized void setRenderObjectPr(long renderObjectPr) {
-    if(this.renderObjectPr != renderObjectPr){
-      if(this.renderObjectPr != 0){
-        throw  new  RuntimeException("RenderObjectPr has " + renderObjectPr + " old renderObjectPtr " + this.renderObjectPr);
-      }
-      this.renderObjectPr = renderObjectPr;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/BasicGraphicAction.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/BasicGraphicAction.java
deleted file mode 100644
index e232584..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/BasicGraphicAction.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.text.TextUtils;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.utils.WXLogUtils;
-
-public abstract class BasicGraphicAction implements IExecutable, Runnable {
-
-  private WXSDKInstance mInstance;
-  private final String mRef;
-  public int mActionType = ActionTypeNormal;
-  public static final int ActionTypeBatchBegin = 1;
-  public static final int ActionTypeBatchEnd = 2;
-  public static final int ActionTypeNormal = 0;
-
-
-  public BasicGraphicAction(WXSDKInstance instance, String ref) {
-    this.mInstance = instance;
-    this.mRef = ref;
-  }
-
-  public final WXSDKInstance getWXSDKIntance() {
-    return mInstance;
-  }
-
-  public final String getPageId() {
-    return mInstance.getInstanceId();
-  }
-
-  public final String getRef() {
-    return mRef;
-  }
-
-  public void executeActionOnRender() {
-    if (TextUtils.isEmpty(mInstance.getInstanceId())) {
-        WXLogUtils.e("[BasicGraphicAction] pageId can not be null");
-        if (WXEnvironment.isApkDebugable()) {
-            throw new RuntimeException("["+getClass().getName()+"] pageId can not be null");
-        }
-        return;
-    }
-    WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(mInstance.getInstanceId(), this);
-  }
-
-  @Override
-  public void run() {
-    try {
-      executeAction();
-    } catch (Throwable e) {
-      //catch everything may throw from exection.
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e("BasicGraphicAction",
-            "SafeRunnable run throw expection:" + e.getMessage());
-        throw e;
-      }
-      WXLogUtils.w("BasicGraphicAction", e);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAbstractAddElement.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAbstractAddElement.java
deleted file mode 100644
index 88baced..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAbstractAddElement.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.v4.util.ArrayMap;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXComponentFactory;
-import com.taobao.weex.ui.component.WXVContainer;
-import java.util.Map;
-import java.util.Set;
-
-public abstract class GraphicActionAbstractAddElement extends BasicGraphicAction {
-
-  protected String mComponentType;
-  protected String mParentRef;
-  protected int mIndex = -1;
-  protected Map<String, String> mStyle;
-  protected Map<String, String> mAttributes;
-  protected Set<String> mEvents;
-  protected float[] mMargins;
-  protected float[] mPaddings;
-  protected float[] mBorders;
-  private long startTime;
-
-  public GraphicActionAbstractAddElement(WXSDKInstance instance, String ref) {
-    super(instance, ref);
-    startTime = System.currentTimeMillis();
-  }
-
-  protected WXComponent createComponent(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    long createComponentStart = System.currentTimeMillis();
-    if (basicComponentData != null) {
-      basicComponentData.addStyle(mStyle);
-      basicComponentData.addAttr(mAttributes);
-      basicComponentData.addEvent(mEvents);
-      basicComponentData.addShorthand(mMargins, CSSShorthand.TYPE.MARGIN);
-      basicComponentData.addShorthand(mPaddings, CSSShorthand.TYPE.PADDING);
-      basicComponentData.addShorthand(mBorders, CSSShorthand.TYPE.BORDER);
-    }
-
-    WXComponent component = WXComponentFactory.newInstance(instance, parent, basicComponentData);
-    WXSDKManager.getInstance().getWXRenderManager().registerComponent(getPageId(), getRef(), component);
-    if(mStyle != null && mStyle.containsKey(Constants.Name.TRANSFORM) && component.getTransition() == null) {
-      Map<String, Object> animationMap = new ArrayMap<>(2);
-      animationMap.put(Constants.Name.TRANSFORM, mStyle.get(Constants.Name.TRANSFORM));
-      animationMap
-          .put(Constants.Name.TRANSFORM_ORIGIN, mStyle.get(Constants.Name.TRANSFORM_ORIGIN));
-      component.addAnimationForElement(animationMap);
-    }
-    instance.onComponentCreate(component,System.currentTimeMillis() -createComponentStart);
-    return component;
-  }
-
-  @Override
-  public void executeAction() {
-    getWXSDKIntance().callActionAddElementTime(System.currentTimeMillis() - startTime);
-  }
-
-  public String getComponentType() {
-    return mComponentType;
-  }
-
-  public String getParentRef() {
-    return mParentRef;
-  }
-
-  public int getIndex() {
-    return mIndex;
-  }
-
-  public Map<String, String> getStyle() {
-    return mStyle;
-  }
-
-  public Map<String, String> getAttributes() {
-    return mAttributes;
-  }
-
-  public Set<String> getEvents() {
-    return mEvents;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddChildToRichtext.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddChildToRichtext.java
deleted file mode 100755
index bddad36..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddChildToRichtext.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-import android.util.Log;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.richtext.WXRichText;
-
-import java.util.HashMap;
-
-public class GraphicActionAddChildToRichtext extends BasicGraphicAction {
-
-    public GraphicActionAddChildToRichtext(@NonNull WXSDKInstance instance, String nodeType, String ref, String parentRef, String richTextRef,
-                                           HashMap<String, String> styles, HashMap<String, String> attrs){
-        super(instance,richTextRef);
-        if(WXSDKManager.getInstance() != null && WXSDKManager.getInstance().getWXRenderManager() != null) {
-            WXRichText richText = (WXRichText) WXSDKManager.getInstance().getWXRenderManager()
-                    .getWXComponent(getPageId(), richTextRef);
-            if (richText != null) {
-                richText.AddChildNode(ref, nodeType, parentRef, styles, attrs);
-            }
-        }
-    }
-    @Override
-    public void executeAction() {
-
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddElement.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddElement.java
deleted file mode 100644
index a0b2005..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddElement.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.support.annotation.WorkerThread;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import android.util.Log;
-import com.taobao.weex.BuildConfig;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.dom.transition.WXTransition;
-import com.taobao.weex.performance.WXAnalyzerDataTransfer;
-import com.taobao.weex.performance.WXStateRecord;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-public class GraphicActionAddElement extends GraphicActionAbstractAddElement {
-
-  private WXVContainer parent;
-  private WXComponent child;
-  private GraphicPosition layoutPosition;
-  private GraphicSize layoutSize;
-  private boolean isLayoutRTL;
-
-  public GraphicActionAddElement(@NonNull WXSDKInstance instance, String ref,
-                                 String componentType, String parentRef,
-                                 int index,
-                                 Map<String, String> style,
-                                 Map<String, String> attributes,
-                                 Set<String> events,
-                                 float[] margins,
-                                 float[] paddings,
-                                 float[] borders) {
-    super(instance, ref);
-    this.mComponentType = componentType;
-    this.mParentRef = parentRef;
-    this.mIndex = index;
-    this.mStyle = style;
-    this.mAttributes = attributes;
-    this.mEvents = events;
-    this.mPaddings = paddings;
-    this.mMargins = margins;
-    this.mBorders = borders;
-
-    if (instance.getContext() == null) {
-      return;
-    }
-      if (WXAnalyzerDataTransfer.isInteractionLogOpen()){
-        Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][addelementStart]"+instance.getInstanceId()+","+componentType+","+ref);
-      }
-    try {
-      parent = (WXVContainer) WXSDKManager.getInstance().getWXRenderManager()
-          .getWXComponent(getPageId(), mParentRef);
-      long start = WXUtils.getFixUnixTime();
-      BasicComponentData basicComponentData = new BasicComponentData(ref, mComponentType,
-          mParentRef);
-      child = createComponent(instance, parent, basicComponentData);
-      child.setTransition(WXTransition.fromMap(child.getStyles(), child));
-      long diff = WXUtils.getFixUnixTime()-start;
-      instance.getApmForInstance().componentCreateTime += diff;
-      if (null != parent && parent.isIgnoreInteraction){
-        child.isIgnoreInteraction = true;
-      }
-      if (!child.isIgnoreInteraction ){
-        Object flag = null;
-        if (null != child.getAttrs()){
-          flag = child.getAttrs().get("ignoreInteraction");
-        }
-        if ("false".equals(flag) || "0".equals(flag)){
-          child.isIgnoreInteraction = false;
-        }else if ("1".equals(flag) || "true".equals(flag) || child.isFixed()){
-          child.isIgnoreInteraction = true;
-        }
-      }
-      WXStateRecord.getInstance().recordAction(instance.getInstanceId(),"addElement");
-
-    } catch (ClassCastException e) {
-      Map<String, String> ext = new ArrayMap<>();
-      WXComponent parent = WXSDKManager.getInstance().getWXRenderManager()
-          .getWXComponent(getPageId(), mParentRef);
-
-      if (mStyle != null && !mStyle.isEmpty()) {
-        ext.put("child.style", mStyle.toString());
-      }
-      if (parent != null && parent.getStyles() != null && !parent.getStyles().isEmpty()) {
-        ext.put("parent.style", parent.getStyles().toString());
-      }
-
-      if (mAttributes != null && !mAttributes.isEmpty()) {
-        ext.put("child.attr", mAttributes.toString());
-      }
-      if (parent != null && parent.getAttrs() != null && !parent.getAttrs().isEmpty()) {
-        ext.put("parent.attr", parent.getAttrs().toString());
-      }
-
-      if (mEvents != null && !mEvents.isEmpty()) {
-        ext.put("child.event", mEvents.toString());
-      }
-      if (parent != null && parent.getEvents() != null && !parent.getEvents().isEmpty()) {
-        ext.put("parent.event", parent.getEvents().toString());
-      }
-
-      if (mMargins != null && mMargins.length > 0) {
-        ext.put("child.margin", Arrays.toString(mMargins));
-      }
-      if (parent != null && parent.getMargin() != null) {
-        ext.put("parent.margin", parent.getMargin().toString());
-      }
-
-      if (mPaddings != null && mPaddings.length > 0) {
-        ext.put("child.padding", Arrays.toString(mPaddings));
-      }
-      if (parent != null && parent.getPadding() != null) {
-        ext.put("parent.padding", parent.getPadding().toString());
-      }
-
-      if (mBorders != null && mBorders.length > 0) {
-        ext.put("child.border", Arrays.toString(mBorders));
-      }
-      if (parent != null && parent.getBorder() != null) {
-        ext.put("parent.border", parent.getBorder().toString());
-      }
-
-      WXExceptionUtils.commitCriticalExceptionRT(instance.getInstanceId(),
-          WXErrorCode.WX_RENDER_ERR_CONTAINER_TYPE,
-          "GraphicActionAddElement",
-          String.format(Locale.ENGLISH,"You are trying to add a %s to a %2$s, which is illegal as %2$s is not a container",
-              componentType,
-              WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), mParentRef).getComponentType()),
-          ext);
-    }
-
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  @WorkerThread
-  public void setRTL(boolean isRTL){
-    this.isLayoutRTL = isRTL;
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  @WorkerThread
-  public void setSize(GraphicSize graphicSize){
-    this.layoutSize = graphicSize;
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  @WorkerThread
-  public void setPosition(GraphicPosition position){
-    this.layoutPosition = position;
-  }
-
-  @RestrictTo(Scope.LIBRARY)
-  @WorkerThread
-  public void setIndex(int index){
-    mIndex = index;
-  }
-
-  @Override
-  public void executeAction() {
-    super.executeAction();
-    try {
-      if (!TextUtils.equals(mComponentType, "video") && !TextUtils.equals(mComponentType, "videoplus"))
-        child.mIsAddElementToTree = true;
-
-      long start = WXUtils.getFixUnixTime();
-      parent.addChild(child, mIndex);
-      parent.createChildViewAt(mIndex);
-
-      child.setIsLayoutRTL(isLayoutRTL);
-      if(layoutPosition !=null && layoutSize != null) {
-        child.setDemission(layoutSize, layoutPosition);
-      }
-      child.applyLayoutAndEvent(child);
-      child.bindData(child);
-      long diff = WXUtils.getFixUnixTime() - start;
-      if (null != getWXSDKIntance()){
-        getWXSDKIntance().getApmForInstance().viewCreateTime +=diff;
-      }
-
-    } catch (Exception e) {
-      WXLogUtils.e("add component failed.", e);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddEvent.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddEvent.java
deleted file mode 100644
index 3ef4a6c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAddEvent.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.tracing.Stopwatch;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by listen on 18/01/11.
- */
-public class GraphicActionAddEvent extends BasicGraphicAction {
-
-  private final String mEvent;
-
-  public GraphicActionAddEvent(WXSDKInstance instance, String ref, Object event) {
-    super(instance, ref);
-    this.mEvent = WXEvent.getEventName(event);
-  }
-
-  @Override
-  public void executeAction() {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      return;
-    }
-
-    Stopwatch.tick();
-    if (!component.getEvents().contains(mEvent)) {
-      component.getEvents().addEvent(mEvent);
-    }
-    component.addEvent(mEvent);
-    Stopwatch.split("addEventToComponent");
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAnimation.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAnimation.java
deleted file mode 100644
index 4023b0c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAnimation.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ArgbEvaluator;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.view.animation.PathInterpolatorCompat;
-import android.text.TextUtils;
-import android.util.Pair;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.animation.BackgroundColorProperty;
-import com.taobao.weex.ui.animation.HeightProperty;
-import com.taobao.weex.ui.animation.WXAnimationBean;
-import com.taobao.weex.ui.animation.WXAnimationModule;
-import com.taobao.weex.ui.animation.WidthProperty;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.list.template.TemplateDom;
-import com.taobao.weex.ui.view.border.BorderDrawable;
-import com.taobao.weex.utils.SingleFunctionParser;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.HashMap;
-import java.util.List;
-
-public class GraphicActionAnimation extends BasicGraphicAction {
-
-  private final static String TAG = "GraphicActionAnimation";
-
-  private final boolean styleNeedInit;
-
-  @Nullable
-  private
-  final String callback;
-
-  @Nullable
-  private
-  WXAnimationBean mAnimationBean;
-
-  public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref, @NonNull WXAnimationBean animationBean) {
-    super(instance, ref);
-    this.styleNeedInit = false;
-    this.callback = null;
-    this.mAnimationBean = animationBean;
-  }
-
-  public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref, @Nullable String animation,
-                                @Nullable final String callBack) {
-    super(instance, ref);
-    this.styleNeedInit = true;
-    this.callback = callBack;
-    if (!TextUtils.isEmpty(animation)) {
-      this.mAnimationBean = JSONObject.parseObject(animation, WXAnimationBean.class);
-    }
-  }
-  public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref, @NonNull WXAnimationBean animationBean,
-                                @Nullable final String callBack) {
-    super(instance, ref);
-    this.styleNeedInit = false;
-    this.mAnimationBean = animationBean;
-    this.callback = callBack;
-  }
-
-  @Override
-  public void executeAction() {
-    if (null == mAnimationBean) {
-      return;
-    }
-
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      if(!TemplateDom.isVirtualDomRef(getRef())){
-        return;
-      }
-      component = TemplateDom.findVirtualComponentByVRef(getPageId(), getRef());
-      if(component == null){
-        return;
-      }
-    }
-
-    WXSDKInstance instance = WXSDKManager.getInstance().getWXRenderManager().getWXSDKInstance(getPageId());
-    if (instance == null) {
-      return;
-    }
-
-    if (null != mAnimationBean.styles) {
-      if(styleNeedInit) {
-        // Synchronize transformOrigin between component styles and animation style before
-        // animation start.
-        String transformOrigin = (String) component.getStyles().get(Constants.Name.TRANSFORM_ORIGIN);
-        if (TextUtils.isEmpty(mAnimationBean.styles.transformOrigin)) {
-          mAnimationBean.styles.transformOrigin = transformOrigin;
-        }
-        mAnimationBean.styles.init(mAnimationBean.styles.transformOrigin,
-            mAnimationBean.styles.transform, (int) component.getLayoutWidth(),
-            (int) component.getLayoutHeight(),
-            instance.getInstanceViewPortWidth(), instance);
-      }
-      startAnimation(instance, component);
-    }
-  }
-
-
-
-  private void startAnimation(@NonNull WXSDKInstance instance, @Nullable WXComponent component) {
-    if (component != null) {
-      if (mAnimationBean != null) {
-        component.setNeedLayoutOnAnimation(mAnimationBean.needLayout);
-      }
-      if (component.getHostView() == null) {
-        WXAnimationModule.AnimationHolder holder = new WXAnimationModule.AnimationHolder(mAnimationBean, callback);
-        component.postAnimation(holder);
-      } else {
-        try {
-          Animator animator = createAnimator(component.getHostView(), instance
-              .getInstanceViewPortWidth());
-          if (animator != null) {
-            Animator.AnimatorListener animatorCallback = createAnimatorListener(instance, callback);
-            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2 && component
-                .isLayerTypeEnabled() ) {
-              component.getHostView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            }
-            Interpolator interpolator = createTimeInterpolator();
-            if (animatorCallback != null) {
-              animator.addListener(animatorCallback);
-            }
-            if (interpolator != null) {
-              animator.setInterpolator(interpolator);
-            }
-            component.getHostView().setCameraDistance(mAnimationBean.styles.getCameraDistance());
-            animator.setDuration(mAnimationBean.duration);
-            animator.start();
-          }
-        } catch (RuntimeException e) {
-          WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
-        }
-      }
-    }
-  }
-
-  private
-  @Nullable
-  ObjectAnimator createAnimator(final View target, final int viewPortWidth) {
-    if (target == null) {
-      return null;
-    }
-    WXAnimationBean.Style style = mAnimationBean.styles;
-    if (style != null) {
-      ObjectAnimator animator;
-      List<PropertyValuesHolder> holders = style.getHolders();
-      if (!TextUtils.isEmpty(style.backgroundColor)) {
-        BorderDrawable borderDrawable;
-        if ((borderDrawable = WXViewUtils.getBorderDrawable(target)) != null) {
-          holders.add(PropertyValuesHolder.ofObject(
-              new BackgroundColorProperty(), new ArgbEvaluator(),
-              borderDrawable.getColor(),
-              WXResourceUtils.getColor(style.backgroundColor)));
-        } else if (target.getBackground() instanceof ColorDrawable) {
-          holders.add(PropertyValuesHolder.ofObject(
-              new BackgroundColorProperty(), new ArgbEvaluator(),
-              ((ColorDrawable) target.getBackground()).getColor(),
-              WXResourceUtils.getColor(style.backgroundColor)));
-        }
-      }
-
-      if (target.getLayoutParams() != null &&
-          (!TextUtils.isEmpty(style.width) || !TextUtils.isEmpty(style.height))) {
-        ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
-        if (!TextUtils.isEmpty(style.width)) {
-          holders.add(PropertyValuesHolder.ofInt(new WidthProperty(), layoutParams.width,
-              (int) WXViewUtils.getRealPxByWidth(WXUtils.getFloat(style.width), viewPortWidth)));
-        }
-        if (!TextUtils.isEmpty(style.height)) {
-          holders.add(PropertyValuesHolder.ofInt(new HeightProperty(), layoutParams.height,
-              (int) WXViewUtils.getRealPxByWidth(WXUtils.getFloat(style.height), viewPortWidth)));
-        }
-      }
-
-      if (style.getPivot() != null) {
-        Pair<Float, Float> pair = style.getPivot();
-        target.setPivotX(pair.first);
-        target.setPivotY(pair.second);
-      }
-      animator = ObjectAnimator.ofPropertyValuesHolder(
-          target, holders.toArray(new PropertyValuesHolder[holders.size()]));
-      animator.setStartDelay(mAnimationBean.delay);
-      return animator;
-    } else {
-      return null;
-    }
-  }
-
-  private
-  @Nullable
-  Animator.AnimatorListener createAnimatorListener(final WXSDKInstance instance, @Nullable final String callBack) {
-    if (!TextUtils.isEmpty(callBack)) {
-      return new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-          if (instance == null || instance.isDestroy()) {
-            WXLogUtils.e("RenderContextImpl-onAnimationEnd WXSDKInstance == null NPE or instance is destroyed");
-          } else {
-            WXSDKManager.getInstance().callback(instance.getInstanceId(),
-                                                callBack,
-                                                new HashMap<String, Object>());
-          }
-        }
-      };
-    } else {
-      return null;
-    }
-  }
-
-  private
-  @Nullable
-  Interpolator createTimeInterpolator() {
-    String interpolator = mAnimationBean.timingFunction;
-    if (!TextUtils.isEmpty(interpolator)) {
-      switch (interpolator) {
-        case WXAnimationBean.EASE_IN:
-          return new AccelerateInterpolator();
-        case WXAnimationBean.EASE_OUT:
-          return new DecelerateInterpolator();
-        case WXAnimationBean.EASE_IN_OUT:
-          return new AccelerateDecelerateInterpolator();
-        case WXAnimationBean.LINEAR:
-          return new LinearInterpolator();
-        default:
-          //Parse cubic-bezier
-          try {
-            SingleFunctionParser<Float> parser = new SingleFunctionParser<>(
-                mAnimationBean.timingFunction,
-                new SingleFunctionParser.FlatMapper<Float>() {
-                  @Override
-                  public Float map(String raw) {
-                    return Float.parseFloat(raw);
-                  }
-                });
-            List<Float> params = parser.parse(WXAnimationBean.CUBIC_BEZIER);
-            if (params != null && params.size() == WXAnimationBean.NUM_CUBIC_PARAM) {
-              return PathInterpolatorCompat.create(
-                  params.get(0), params.get(1), params.get(2), params.get(3));
-            } else {
-              return null;
-            }
-          } catch (RuntimeException e) {
-            return null;
-          }
-      }
-    }
-    return null;
-  }
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAppendTreeCreateFinish.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAppendTreeCreateFinish.java
deleted file mode 100644
index 0fe09f0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionAppendTreeCreateFinish.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-
-/**
- * Created by listen on 18/01/09.
- */
-public class GraphicActionAppendTreeCreateFinish extends BasicGraphicAction {
-
-  WXComponent component;
-
-  public GraphicActionAppendTreeCreateFinish(WXSDKInstance instance, String ref) {
-    super(instance, ref);
-
-    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), ref);
-    if (null != component && component instanceof WXVContainer) {
-      ((WXVContainer)component).appendTreeCreateFinish();
-    }
-  }
-
-  @Override
-  public void executeAction() {
-
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchAction.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchAction.java
deleted file mode 100644
index 901db40..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchAction.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class GraphicActionBatchAction extends BasicGraphicAction {
-    private List<BasicGraphicAction> mActions;
-
-    public GraphicActionBatchAction(WXSDKInstance instance, String ref, List<BasicGraphicAction> mActions) {
-        super(instance, ref);
-        this.mActions = new ArrayList<>(mActions);
-    }
-
-    @Override
-    public void executeAction() {
-        for (int i = 0;i < mActions.size();i ++) {
-            mActions.get(i).executeAction();
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchBegin.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchBegin.java
deleted file mode 100644
index d61540a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchBegin.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-
-public class GraphicActionBatchBegin extends BasicGraphicAction {
-    public GraphicActionBatchBegin(WXSDKInstance instance, String ref) {
-        super(instance, ref);
-        this.mActionType = ActionTypeBatchBegin;
-    }
-
-    @Override
-    public void executeAction() {
-
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchEnd.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchEnd.java
deleted file mode 100644
index 45d9744..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionBatchEnd.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-
-public class GraphicActionBatchEnd extends BasicGraphicAction {
-    public GraphicActionBatchEnd(WXSDKInstance instance, String ref) {
-        super(instance, ref);
-        this.mActionType = ActionTypeBatchEnd;
-    }
-
-    @Override
-    public void executeAction() {
-
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionCreateBody.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionCreateBody.java
deleted file mode 100644
index 49eef03..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionCreateBody.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-import android.widget.ScrollView;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.dom.transition.WXTransition;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXScroller;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.Map;
-import java.util.Set;
-
-public class GraphicActionCreateBody extends GraphicActionAbstractAddElement {
-
-  private WXComponent component;
-
-  public GraphicActionCreateBody(@NonNull WXSDKInstance instance, String ref,
-                                 String componentType,
-                                 Map<String, String> style,
-                                 Map<String, String> attributes,
-                                 Set<String> events,
-                                 float[] margins,
-                                 float[] paddings,
-                                 float[] borders) {
-    super(instance, ref);
-    this.mComponentType = componentType;
-    this.mStyle = style;
-    this.mAttributes = attributes;
-    this.mEvents = events;
-    this.mMargins = margins;
-    this.mPaddings = paddings;
-    this.mBorders = borders;
-
-    if (instance.getContext() == null) {
-      return;
-    }
-
-    BasicComponentData basicComponentData = new BasicComponentData(getRef(), mComponentType, null);
-    component = createComponent(instance, null, basicComponentData);
-    if (component == null) {
-      return;
-    }
-    component.setTransition(WXTransition.fromMap(component.getStyles(), component));
-  }
-
-  @Override
-  public void executeAction() {
-    super.executeAction();
-    try {
-      component.createView();
-      component.applyLayoutAndEvent(component);
-      component.bindData(component);
-      WXSDKInstance instance = getWXSDKIntance();
-
-      if (component instanceof WXScroller) {
-        WXScroller scroller = (WXScroller) component;
-        if (scroller.getInnerView() instanceof ScrollView) {
-          instance.setRootScrollView((ScrollView) scroller.getInnerView());
-        }
-      }
-
-      instance.onRootCreated(component);
-
-      if (instance.getRenderStrategy() != WXRenderStrategy.APPEND_ONCE) {
-        instance.onCreateFinish();
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("create body failed.", e);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionCreateFinish.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionCreateFinish.java
deleted file mode 100644
index c768b08..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionCreateFinish.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.RenderTypes;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by listen on 18/01/09.
- */
-public class GraphicActionCreateFinish extends BasicGraphicAction {
-
-  private int mLayoutWidth;
-  private int mLayoutHeight;
-
-  public GraphicActionCreateFinish(@NonNull WXSDKInstance instance) {
-    super(instance, "");
-    WXComponent component = instance.getRootComponent();
-    if (null != component) {
-        this.mLayoutWidth = (int) component.getLayoutWidth();
-        this.mLayoutHeight = (int) component.getLayoutHeight();
-    }
-    instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_CREATE_FINISH);
-    instance.getApmForInstance().extInfo.put(WXInstanceApm.KEY_PAGE_STAGES_CREATE_FINISH,true);
-  }
-
-  @Override
-  public void executeAction() {
-    final WXSDKInstance instance = getWXSDKIntance();
-    if (instance == null || instance.getContext() == null) {
-      return;
-    }
-    if(instance.mHasCreateFinish){
-        return;
-    }
-
-    if (instance.getRenderStrategy() == WXRenderStrategy.APPEND_ONCE) {
-      instance.onCreateFinish();
-    }else{
-      if(!RenderTypes.RENDER_TYPE_NATIVE.equals(instance.getRenderType())){
-          instance.onCreateFinish();
-      }
-    }
-
-    instance.mHasCreateFinish = true;
-
-    if (null != instance.getWXPerformance()){
-      instance.getWXPerformance().callCreateFinishTime = System.currentTimeMillis()-instance.getWXPerformance().renderTimeOrigin;
-    }
-    instance.onOldFsRenderTimeLogic();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionLayout.java
deleted file mode 100644
index cffef17..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionLayout.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.WXComponent;
-
-public class GraphicActionLayout extends BasicGraphicAction {
-
-  private final GraphicPosition mLayoutPosition;
-  private final GraphicSize mLayoutSize;
-  private final boolean mIsLayoutRTL;
-
-  public GraphicActionLayout(WXSDKInstance instance, String ref, GraphicPosition layoutPosition, GraphicSize layoutSize, boolean isRTL) {
-    super(instance, ref);
-    this.mLayoutPosition = layoutPosition;
-    this.mLayoutSize = layoutSize;
-    this.mIsLayoutRTL = isRTL;
-  }
-
-  @Override
-  public void executeAction() {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      return;
-    }
-
-    component.setIsLayoutRTL(mIsLayoutRTL);
-    component.setDemission(mLayoutSize, mLayoutPosition);
-    component.setSafeLayout(component);
-    component.setPadding(component.getPadding(), component.getBorder());
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionMoveElement.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionMoveElement.java
deleted file mode 100644
index 424ee84..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionMoveElement.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-
-public class GraphicActionMoveElement extends BasicGraphicAction {
-
-  private String mParentref;
-  private int mIndex;
-
-  public GraphicActionMoveElement(WXSDKInstance instance, String ref, String parentRef, int index) {
-    super(instance, ref);
-    this.mParentref = parentRef;
-    this.mIndex = index;
-  }
-
-  @Override
-  public void executeAction() {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if(component == null) {
-      return;
-    }
-    WXVContainer oldParent = component.getParent();
-    WXComponent newParent = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), mParentref);
-    if (oldParent == null
-            || newParent == null || !(newParent instanceof WXVContainer)) {
-      return;
-    }
-
-    if (component.getHostView() != null && !TextUtils.equals(component.getComponentType(), "video") && !TextUtils.equals(component.getComponentType(), "videoplus")) {
-      int[] location = new  int[2] ;
-      component.getHostView().getLocationInWindow(location);
-    }
-
-    oldParent.remove(component, false);
-
-    ((WXVContainer) newParent).addChild(component, mIndex);
-
-    if (component.getHostView() != null && !TextUtils.equals(component.getComponentType(), "video") && !TextUtils.equals(component.getComponentType(), "videoplus")) {
-      int[] location = new  int[2] ;
-      component.getHostView().getLocationInWindow(location);
-    }
-
-    if (!component.isVirtualComponent()) {
-      ((WXVContainer) newParent).addSubView(component.getHostView(), mIndex);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRefreshFinish.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRefreshFinish.java
deleted file mode 100644
index 0cc78bf..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRefreshFinish.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by listen on 18/01/09.
- */
-public class GraphicActionRefreshFinish extends BasicGraphicAction {
-
-  private int mLayoutWidth;
-  private int mLayoutHeight;
-
-  public GraphicActionRefreshFinish(@NonNull WXSDKInstance instance) {
-    super(instance, "");
-    WXComponent component = instance.getRootComponent();
-    if (null != component) {
-        this.mLayoutWidth = (int) component.getLayoutWidth();
-        this.mLayoutHeight = (int) component.getLayoutHeight();
-    }
-  }
-
-  @Override
-  public void executeAction() {
-    final WXSDKInstance instance = getWXSDKIntance();
-    if (instance == null || instance.getContext() == null) {
-      return;
-    }
-
-    instance.onRefreshSuccess(mLayoutWidth, mLayoutHeight);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveChildFromRichtext.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveChildFromRichtext.java
deleted file mode 100755
index 5c5cf2c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveChildFromRichtext.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.richtext.WXRichText;
-import com.taobao.weex.ui.component.richtext.node.RichTextNode;
-
-public class GraphicActionRemoveChildFromRichtext extends BasicGraphicAction{
-    private String ref;
-    private String parentRef;
-    private WXRichText richText;
-    public GraphicActionRemoveChildFromRichtext(WXSDKInstance instance,String ref,String parentRef,String richtextRef){
-        super(instance, richtextRef);
-        this.ref = ref;
-        this.parentRef = parentRef;
-        richText = (WXRichText) WXSDKManager.getInstance().getWXRenderManager().
-                getWXComponent(instance.getInstanceId(),richtextRef);
-        if(richText != null){
-            richText.removeChildNode(parentRef,ref);
-        }
-    }
-    @Override
-    public void executeAction() {
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveElement.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveElement.java
deleted file mode 100644
index b7e4551..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveElement.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-
-public class GraphicActionRemoveElement extends BasicGraphicAction {
-
-  public GraphicActionRemoveElement(WXSDKInstance instance, String ref) {
-    super(instance, ref);
-  }
-
-  @Override
-  public void executeAction() {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null || component.getParent() == null || component.getInstance() == null) {
-      return;
-    }
-    clearRegistryForComponent(component);
-    WXVContainer parent = component.getParent();
-
-    if (component.getHostView() != null && !TextUtils.equals(component.getComponentType(), "video") && !TextUtils.equals(component.getComponentType(), "videoplus")) {
-      int[] location = new  int[2];
-      component.getHostView().getLocationInWindow(location);
-      //component.getInstance().onChangeElement(parent, location[1] > component.getInstance().getWeexHeight() + 1);
-    }
-
-    parent.remove(component, true);
-  }
-
-  private void clearRegistryForComponent(WXComponent component) {
-    WXComponent removedComponent = WXSDKManager.getInstance().getWXRenderManager().unregisterComponent(getPageId(), getRef());
-    if (removedComponent != null) {
-      removedComponent.removeAllEvent();
-      removedComponent.removeStickyStyle();
-    }
-    if (component instanceof WXVContainer) {
-      WXVContainer container = (WXVContainer) component;
-      int count = container.childCount();
-      for (int i = count - 1; i >= 0; --i) {
-        clearRegistryForComponent(container.getChild(i));
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveEvent.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveEvent.java
deleted file mode 100644
index 67fe133..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRemoveEvent.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.tracing.Stopwatch;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by listen on 18/01/11.
- */
-public class GraphicActionRemoveEvent extends BasicGraphicAction {
-
-  private final String mEvent;
-
-  public GraphicActionRemoveEvent(WXSDKInstance instance, String ref, Object event) {
-    super(instance, ref);
-    this.mEvent = WXEvent.getEventName(event);
-  }
-
-  @Override
-  public void executeAction() {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      return;
-    }
-
-    Stopwatch.tick();
-    component.removeEvent(mEvent);
-    Stopwatch.split("removeEventFromComponent");
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRenderSuccess.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRenderSuccess.java
deleted file mode 100644
index ecd12b1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionRenderSuccess.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.annotation.NonNull;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.component.WXComponent;
-
-public class GraphicActionRenderSuccess extends BasicGraphicAction {
-
-    public GraphicActionRenderSuccess(@NonNull WXSDKInstance instance) {
-        super(instance, "");
-    }
-
-    @Override
-    public void executeAction() {
-        final WXSDKInstance instance = getWXSDKIntance();
-        if (instance == null || instance.getContext() == null) {
-            return;
-        }
-        WXComponent component = instance.getRootComponent();
-        int layoutWidth = 0;
-        int layoutHeight = 0;
-        if (null != component) {
-            layoutWidth = (int) component.getLayoutWidth();
-            layoutHeight = (int) component.getLayoutHeight();
-        }
-        instance.onRenderSuccess(layoutWidth, layoutHeight);
-    }
-
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionScrollToElement.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionScrollToElement.java
deleted file mode 100644
index c03e930..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionScrollToElement.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.Scrollable;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by listen on 18/01/09.
- */
-public class GraphicActionScrollToElement extends BasicGraphicAction {
-
-  private final JSONObject mOptions;
-
-  public GraphicActionScrollToElement(WXSDKInstance instance, String ref, JSONObject options) {
-    super(instance, ref);
-    this.mOptions = options;
-  }
-
-  @Override
-  public void executeAction() {
-    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      return;
-    }
-
-    Scrollable scroller = component.getParentScroller();
-    if (scroller == null) {
-      return;
-    }
-    scroller.scrollTo(component, mOptions);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateAttr.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateAttr.java
deleted file mode 100644
index 4e6a00f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateAttr.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.WXComponent;
-
-import java.util.Map;
-
-public class GraphicActionUpdateAttr extends BasicGraphicAction {
-
-  private Map<String, String> mAttrs;
-  private WXComponent component;
-
-  public GraphicActionUpdateAttr(WXSDKInstance instance, String ref,
-                                 Map<String, String> attrs) {
-    super(instance, ref);
-    this.mAttrs = attrs;
-
-    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      return;
-    }
-    if (mAttrs != null) {
-      component.addAttr(mAttrs);
-    }
-  }
-
-  @Override
-  public void executeAction() {
-    if (component == null) {
-      return;
-    }
-    component.getAttrs().mergeAttr();
-    component.updateAttrs(mAttrs);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateRichtextAttr.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateRichtextAttr.java
deleted file mode 100755
index 3c30eb5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateRichtextAttr.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.richtext.WXRichText;
-import java.util.HashMap;
-import java.util.Map;
-
-public class GraphicActionUpdateRichtextAttr extends BasicGraphicAction{
-
-    public GraphicActionUpdateRichtextAttr(WXSDKInstance instance, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef){
-        super(instance, richTextRef);
-        WXRichText richText =  (WXRichText) WXSDKManager.getInstance().getWXRenderManager()
-                .getWXComponent(getPageId(), richTextRef);
-        if(richText != null) {
-            Map<String, Object> map = new HashMap<>();
-            map.putAll(attrs);
-            richText.updateChildNodeAttrs(ref, map);
-        }
-    }
-    @Override
-    public void executeAction() {
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateRichtextStyle.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateRichtextStyle.java
deleted file mode 100755
index c5c3231..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateRichtextStyle.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.richtext.WXRichText;
-import com.taobao.weex.ui.component.richtext.node.RichTextNode;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class GraphicActionUpdateRichtextStyle  extends BasicGraphicAction{
-    public GraphicActionUpdateRichtextStyle(WXSDKInstance instance, String ref, HashMap<String, String> styles, String parentRef, String richTextRef){
-        super(instance, richTextRef);
-        WXRichText richText =  (WXRichText) WXSDKManager.getInstance().getWXRenderManager()
-                .getWXComponent(getPageId(), richTextRef);
-        if(richText != null){
-                Map<String, Object> map = new HashMap<>();
-                map.putAll(styles);
-                richText.updateChildNodeStyles(ref, map);
-
-        }
-    }
-    @Override
-    public void executeAction() {
-
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateStyle.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateStyle.java
deleted file mode 100644
index bddb338..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateStyle.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.support.v4.util.ArrayMap;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.dom.transition.WXTransition;
-import com.taobao.weex.ui.component.WXComponent;
-
-import java.util.Map;
-
-public class GraphicActionUpdateStyle extends BasicGraphicAction {
-
-  private Map<String, Object> mStyle;
-  private WXComponent component;
-  private boolean mIsCausedByPesudo;
-  private boolean mIsBorderSet;
-
-  public GraphicActionUpdateStyle(WXSDKInstance instance, String ref,
-                                  Map<String, Object> style,
-                                  Map<String, String> paddings,
-                                  Map<String, String> margins,
-                                  Map<String, String> borders) {
-    this(instance, ref, style, paddings, margins, borders, false);
-  }
-
-  public GraphicActionUpdateStyle(WXSDKInstance instance, String ref,
-                                  Map<String, Object> style,
-                                  CSSShorthand paddings,
-                                  CSSShorthand margins,
-                                  CSSShorthand borders, boolean byPesudo) {
-    super(instance, ref);
-    this.mStyle = style;
-    this.mIsCausedByPesudo = byPesudo;
-
-    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      return;
-    }
-    if (null != mStyle) {
-      component.updateStyle(mStyle, mIsCausedByPesudo);
-      if(style.containsKey(Constants.Name.TRANSFORM) && component.getTransition() == null) {
-        Map<String, Object> animationMap = new ArrayMap<>(2);
-        animationMap.put(Constants.Name.TRANSFORM, style.get(Constants.Name.TRANSFORM));
-        animationMap
-            .put(Constants.Name.TRANSFORM_ORIGIN, style.get(Constants.Name.TRANSFORM_ORIGIN));
-        component.addAnimationForElement(animationMap);
-      }
-    }
-
-    if (null != paddings) {
-      component.setPaddings(paddings);
-    }
-
-    if (null != margins) {
-      component.setMargins(margins);
-    }
-
-    if (null != borders) {
-      mIsBorderSet = true;
-      component.setBorders(borders);
-    }
-  }
-
-  public GraphicActionUpdateStyle(WXSDKInstance instance, String ref,
-                                  Map<String, Object> style,
-                                  Map<String, String> paddings,
-                                  Map<String, String> margins,
-                                  Map<String, String> borders, boolean byPesudo) {
-    super(instance, ref);
-    this.mStyle = style;
-    this.mIsCausedByPesudo = byPesudo;
-
-    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-    if (component == null) {
-      return;
-    }
-    if (null != mStyle) {
-      component.addStyle(mStyle, mIsCausedByPesudo);
-      if(style.containsKey(Constants.Name.TRANSFORM) && component.getTransition() == null){
-        Map<String, Object> animationMap = new ArrayMap<>(2);
-        animationMap.put(Constants.Name.TRANSFORM, style.get(Constants.Name.TRANSFORM));
-        animationMap.put(Constants.Name.TRANSFORM_ORIGIN, style.get(Constants.Name.TRANSFORM_ORIGIN));
-        component.addAnimationForElement(animationMap);
-        WXBridgeManager.getInstance().markDirty(component.getInstanceId(), component.getRef(), true);
-      }
-    }
-
-    if (null != paddings) {
-      component.addShorthand(paddings);
-    }
-
-    if (null != margins) {
-      component.addShorthand(margins);
-    }
-
-    if (null != borders) {
-      mIsBorderSet = true;
-      component.addShorthand(borders);
-    }
-  }
-
-  @Override
-  public void executeAction() {
-    if (component == null) return;
-    if (mStyle != null) {
-      if(component.getTransition() != null){
-        component.getTransition().updateTranstionParams(mStyle);
-        if(component.getTransition().hasTransitionProperty(mStyle)){
-          component.getTransition().startTransition(mStyle);
-        }
-      } else {
-        component.setTransition(WXTransition.fromMap(mStyle, component));
-        component.updateStyles(mStyle);
-      }
-    } else if (mIsBorderSet) {
-      component.updateStyles(component);
-    }
-  }
-}
-
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicPosition.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicPosition.java
deleted file mode 100644
index 9837809..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicPosition.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-public class GraphicPosition {
-
-  private float mLeft;
-  private float mTop;
-  private float mRight;
-  private float mBottom;
-
-  public GraphicPosition(float left, float top, float right, float bottom) {
-    this.mLeft = left;
-    this.mTop = top;
-    this.mRight = right;
-    this.mBottom = bottom;
-  }
-
-  public float getLeft() {
-    return mLeft;
-  }
-
-  public void setLeft(float left) {
-    this.mLeft = left;
-  }
-
-  public float getTop() {
-    return mTop;
-  }
-
-  public void setTop(float top) {
-    this.mTop = top;
-  }
-
-  public float getRight() {
-    return mRight;
-  }
-
-  public void setRight(float right) {
-    this.mRight = right;
-  }
-
-  public float getBottom() {
-    return mBottom;
-  }
-
-  public void setBottom(float bottom) {
-    this.mBottom = bottom;
-  }
-
-
-  public void update(float top, float bottom, float left, float right) {
-    this.mTop = top;
-    this.mBottom = bottom;
-    this.mLeft = left;
-    this.mRight = right;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicSize.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicSize.java
deleted file mode 100644
index 35d6439..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicSize.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-public class GraphicSize {
-
-  private float mWidth;
-  private float mHeight;
-
-  public GraphicSize(float width, float height) {
-    this.mWidth = width;
-    this.mHeight = height;
-  }
-
-  public float getWidth() {
-    return mWidth;
-  }
-
-  public void setWidth(float width) {
-    this.mWidth = width;
-  }
-
-  public float getHeight() {
-    return mHeight;
-  }
-
-  public void setHeight(float height) {
-    this.mHeight = height;
-  }
-
-  public void update(float width, float height) {
-    this.mWidth = width;
-    this.mHeight = height;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/IExecutable.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/IExecutable.java
deleted file mode 100644
index 399d249..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/IExecutable.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-public interface IExecutable {
-
-  void executeAction();
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/UpdateComponentDataAction.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/UpdateComponentDataAction.java
deleted file mode 100644
index b5e412e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/UpdateComponentDataAction.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.action;
-
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.SimpleJSCallback;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.list.template.CellDataManager;
-import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
-import com.taobao.weex.utils.WXLogUtils;
-
-
-/**
- * Created by furture on 2018/1/23.
- */
-
-public class UpdateComponentDataAction extends BasicGraphicAction{
-
-    private String virtualComponentId;
-    private JSONObject data;
-    private String callback;
-
-
-    public UpdateComponentDataAction(WXSDKInstance instance, String virtualComponentId,
-                                     JSONObject data, String callback) {
-        super(instance, CellDataManager.getListRef(virtualComponentId));
-        this.virtualComponentId = virtualComponentId;
-        this.data = data;
-        this.callback = callback;
-    }
-
-    @Override
-    public void executeAction() {
-        if(TextUtils.isEmpty(getRef())){
-            WXLogUtils.e("wrong virtualComponentId split error " + virtualComponentId);
-            return;
-        }
-        WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
-        if(component instanceof WXRecyclerTemplateList){
-            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) component;
-            templateList.getCellDataManager().updateVirtualComponentData(virtualComponentId, data);
-            templateList.notifyUpdateList();
-            SimpleJSCallback jsCallback = new SimpleJSCallback(component.getInstanceId(), callback);
-            jsCallback.invoke(true);
-        }else{
-            WXLogUtils.e("recycler-list wrong virtualComponentId " + virtualComponentId);
-        }
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/BackgroundColorProperty.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/BackgroundColorProperty.java
deleted file mode 100644
index 219f295..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/BackgroundColorProperty.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.util.Property;
-import android.view.View;
-
-import com.taobao.weex.ui.view.border.BorderDrawable;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-public class BackgroundColorProperty extends Property<View, Integer> {
-
-  private final static String TAG = "BackgroundColorAnimation";
-
-  public BackgroundColorProperty() {
-    super(Integer.class, WXAnimationBean.Style.BACKGROUND_COLOR);
-  }
-
-  @Override
-  public Integer get(View object) {
-    int color;
-    BorderDrawable borderDrawable;
-    if ((borderDrawable = WXViewUtils.getBorderDrawable(object)) != null) {
-      color = borderDrawable.getColor();
-    } else if (object.getBackground() instanceof ColorDrawable) {
-      color = ((ColorDrawable) object.getBackground()).getColor();
-    } else {
-      color = Color.TRANSPARENT;
-      WXLogUtils.e(TAG, "Unsupported background type");
-    }
-    return color;
-  }
-
-  @Override
-  public void set(View object, Integer value) {
-    BorderDrawable borderDrawable;
-    if ((borderDrawable = WXViewUtils.getBorderDrawable(object)) != null) {
-      borderDrawable.setColor(value);
-    } else if (object.getBackground() instanceof ColorDrawable) {
-      ((ColorDrawable) object.getBackground()).setColor(value);
-    } else {
-      WXLogUtils.e(TAG, "Unsupported background type");
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/CameraDistanceProperty.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/CameraDistanceProperty.java
deleted file mode 100644
index 67b9235..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/CameraDistanceProperty.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.util.Property;
-import android.view.View;
-
-
-class CameraDistanceProperty extends Property<View, Float> {
-
-  private final static String TAG = "CameraDistance";
-  private static CameraDistanceProperty instance;
-
-  static Property<View, Float> getInstance(){
-    return instance;
-  }
-
-  private CameraDistanceProperty() {
-    super(Float.class, TAG);
-  }
-
-  @Override
-  public Float get(View view) {
-    if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
-      return view.getCameraDistance();
-    }
-    else{
-      return Float.NaN;
-    }
-  }
-
-  @Override
-  public void set(View object, Float value) {
-    object.setCameraDistance(value);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/HeightProperty.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/HeightProperty.java
deleted file mode 100644
index b268ed2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/HeightProperty.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-
-import android.view.ViewGroup.LayoutParams;
-
-public class HeightProperty extends LayoutParamsProperty {
-
-  @Override
-  protected Integer getProperty(LayoutParams layoutParams) {
-    return layoutParams.height;
-  }
-
-  @Override
-  protected void setProperty(LayoutParams layoutParams, Integer expected) {
-    layoutParams.height = expected;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/LayoutParamsProperty.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/LayoutParamsProperty.java
deleted file mode 100644
index 312180e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/LayoutParamsProperty.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-
-import android.util.Property;
-import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.view.IRenderResult;
-
-/**
- * android.util.IntProperty<T> cannot be applied here, as it is only added at API 24.
- */
-abstract class LayoutParamsProperty extends Property<View, Integer> {
-
-  LayoutParamsProperty() {
-    super(Integer.class, "layoutParams");
-  }
-
-  @Override
-  public Integer get(View object) {
-    LayoutParams layoutParams;
-    if (object != null && (layoutParams = object.getLayoutParams()) != null) {
-      return getProperty(layoutParams);
-    }
-    return 0;
-  }
-
-  @Override
-  public void set(View object, Integer value) {
-    LayoutParams layoutParams;
-    if (object != null && (layoutParams = object.getLayoutParams()) != null) {
-      setProperty(layoutParams, value);
-      if (object instanceof IRenderResult) {
-        WXComponent component = ((IRenderResult) object).getComponent();
-        if (component != null) {
-            component.notifyNativeSizeChanged(layoutParams.width, layoutParams.height);
-        }
-      }
-      object.requestLayout();
-    }
-  }
-
-  protected abstract Integer getProperty(LayoutParams layoutParams);
-
-  protected abstract void setProperty(LayoutParams layoutParams, Integer expected);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/TransformParser.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/TransformParser.java
deleted file mode 100644
index 38eb709..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/TransformParser.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-import android.animation.PropertyValuesHolder;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import android.util.Pair;
-import android.util.Property;
-import android.view.View;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.utils.FunctionParser;
-import com.taobao.weex.utils.WXDataStructureUtil;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by furture on 2017/10/24.
- */
-
-public class TransformParser {
-
-    public final static String WX_TRANSLATE = "translate";
-    public final static String WX_TRANSLATE_X = "translateX";
-    public final static String WX_TRANSLATE_Y = "translateY";
-    public final static String WX_ROTATE = "rotate";
-    public final static String WX_ROTATE_X ="rotateX";
-    public final static String WX_ROTATE_Y ="rotateY";
-    public final static String WX_ROTATE_Z ="rotateZ";
-    public final static String WX_SCALE = "scale";
-    public final static String WX_SCALE_X = "scaleX";
-    public final static String WX_SCALE_Y = "scaleY";
-
-    public final static String BACKGROUND_COLOR = Constants.Name.BACKGROUND_COLOR;
-    public final static String WIDTH = Constants.Name.WIDTH;
-    public final static String HEIGHT = Constants.Name.HEIGHT;
-    public final static String TOP = "top";
-    public final static String BOTTOM = "bottom";
-    public final static String RIGHT = "right";
-    public final static String LEFT = "left";
-    public final static String CENTER = "center";
-    private static final String HALF = "50%";
-    private static final String FULL = "100%";
-    private static final String ZERO = "0%";
-    private static final String PX = "px";
-    private static final String DEG = "deg";
-    public static Map<String, List<Property<View,Float>>> wxToAndroidMap = new ArrayMap<>();
-
-
-    static {
-        wxToAndroidMap.put(WX_TRANSLATE, Arrays.asList
-                (View.TRANSLATION_X, View.TRANSLATION_Y));
-        wxToAndroidMap.put(WX_TRANSLATE_X, Collections.singletonList(View.TRANSLATION_X));
-        wxToAndroidMap.put(WX_TRANSLATE_Y, Collections.singletonList(View.TRANSLATION_Y));
-        wxToAndroidMap.put(WX_ROTATE, Collections.singletonList(View.ROTATION));
-        wxToAndroidMap.put(WX_ROTATE_Z, Collections.singletonList(View.ROTATION));
-        wxToAndroidMap.put(WX_ROTATE_X, Collections.singletonList(View.ROTATION_X));
-        wxToAndroidMap.put(WX_ROTATE_Y, Collections.singletonList(View.ROTATION_Y));
-        wxToAndroidMap.put(WX_SCALE, Arrays.asList(View.SCALE_X, View.SCALE_Y));
-        wxToAndroidMap.put(WX_SCALE_X, Collections.singletonList(View.SCALE_X));
-        wxToAndroidMap.put(WX_SCALE_Y, Collections.singletonList(View.SCALE_Y));
-        wxToAndroidMap.put(Constants.Name.PERSPECTIVE, Collections.singletonList(CameraDistanceProperty.getInstance()));
-        wxToAndroidMap = Collections.unmodifiableMap(wxToAndroidMap);
-    }
-
-    public static PropertyValuesHolder[] toHolders(Map<Property<View,Float>, Float> transformMap){
-        PropertyValuesHolder[]  holders = new PropertyValuesHolder[transformMap.size()];
-        int i=0;
-        for (Map.Entry<Property<View, Float>, Float> entry : transformMap.entrySet()) {
-            holders[i] = PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue());
-            i++;
-        }
-        return holders;
-    }
-
-    public static Map<Property<View,Float>, Float> parseTransForm(String instanceId, @Nullable String rawTransform, final int width,
-                                                                  final int height, final int viewportW) {
-        try{
-
-            if (!TextUtils.isEmpty(rawTransform)) {
-                FunctionParser<Property<View,Float>, Float> parser = new FunctionParser<>
-                        (rawTransform, new FunctionParser.Mapper<Property<View,Float>, Float>() {
-                            @Override
-                            public Map<Property<View,Float>, Float> map(String functionName, List<String> raw) {
-                                if (raw != null && !raw.isEmpty()) {
-                                    if (wxToAndroidMap.containsKey(functionName)) {
-                                        return convertParam(width, height,viewportW, wxToAndroidMap.get(functionName), raw);
-                                    }
-                                }
-                                return new HashMap<>();
-                            }
-
-                            private Map<Property<View,Float>, Float> convertParam(int width, int height, int viewportW,
-                                                                                  @NonNull List<Property<View,Float>> propertyList,
-                                                                                  @NonNull List<String> rawValue) {
-
-                                Map<Property<View,Float>, Float> result = WXDataStructureUtil.newHashMapWithExpectedSize(propertyList.size());
-                                List<Float> convertedList = new ArrayList<>(propertyList.size());
-                                if (propertyList.contains(View.ROTATION) ||
-                                        propertyList.contains(View.ROTATION_X) ||
-                                        propertyList.contains(View.ROTATION_Y)) {
-                                    convertedList.addAll(parseRotationZ(rawValue));
-                                }else if (propertyList.contains(View.TRANSLATION_X) ||
-                                        propertyList.contains(View.TRANSLATION_Y)) {
-                                    convertedList.addAll(parseTranslation(propertyList, width, height, rawValue,viewportW));
-                                } else if (propertyList.contains(View.SCALE_X) ||
-                                        propertyList.contains(View.SCALE_Y)) {
-                                    convertedList.addAll(parseScale(propertyList.size(), rawValue));
-                                }
-                                else if(propertyList.contains(CameraDistanceProperty.getInstance())){
-                                    convertedList.add(parseCameraDistance(rawValue));
-                                }
-                                if (propertyList.size() == convertedList.size()) {
-                                    for (int i = 0; i < propertyList.size(); i++) {
-                                        result.put(propertyList.get(i), convertedList.get(i));
-                                    }
-                                }
-                                return result;
-                            }
-
-                            private List<Float> parseScale(int size, @NonNull List<String> rawValue) {
-                                List<Float> convertedList = new ArrayList<>(rawValue.size() * 2);
-                                List<Float> rawFloat = new ArrayList<>(rawValue.size());
-                                for (String item : rawValue) {
-                                    rawFloat.add(WXUtils.fastGetFloat(item));
-                                }
-                                convertedList.addAll(rawFloat);
-                                if (size != 1 && rawValue.size() == 1) {
-                                    convertedList.addAll(rawFloat);
-                                }
-                                return convertedList;
-                            }
-
-                            private @NonNull
-                            List<Float> parseRotationZ(@NonNull List<String> rawValue) {
-                                List<Float> convertedList = new ArrayList<>(1);
-                                int suffix;
-                                for (String raw : rawValue) {
-                                    if ((suffix = raw.lastIndexOf(DEG)) != -1) {
-                                        convertedList.add(WXUtils.fastGetFloat(raw.substring(0, suffix)));
-                                    } else {
-                                        convertedList.add((float) Math.toDegrees(WXUtils.fastGetFloat(raw)));
-                                    }
-                                }
-                                return convertedList;
-                            }
-
-                            /**
-                             * As "translate(50%, 25%)" or "translate(25px, 30px)" both are valid,
-                             * parsing translate is complicated than other method.
-                             * Add your waste time here if you try to optimize this method like {@link #parseScale(int, List)}
-                             * Time: 0.5h
-                             */
-                            private List<Float> parseTranslation(List<Property<View,Float>> propertyList,
-                                                                 int width, int height,
-                                                                 @NonNull List<String> rawValue, int viewportW) {
-                                List<Float> convertedList = new ArrayList<>(2);
-                                String first = rawValue.get(0);
-                                if (propertyList.size() == 1) {
-                                    parseSingleTranslation(propertyList, width, height, convertedList, first,viewportW);
-                                } else {
-                                    parseDoubleTranslation(width, height, rawValue, convertedList, first,viewportW);
-                                }
-                                return convertedList;
-                            }
-
-                            private void parseSingleTranslation(List<Property<View,Float>> propertyList, int width, int height,
-                                                                List<Float> convertedList, String first, int viewportW) {
-                                if (propertyList.contains(View.TRANSLATION_X)) {
-                                    convertedList.add(parsePercentOrPx(first, width,viewportW));
-                                } else if (propertyList.contains(View.TRANSLATION_Y)) {
-                                    convertedList.add(parsePercentOrPx(first, height,viewportW));
-                                }
-                            }
-
-                            private void parseDoubleTranslation(int width, int height,
-                                                                @NonNull List<String> rawValue,
-                                                                List<Float> convertedList, String first, int viewportW) {
-                                String second;
-                                if (rawValue.size() == 1) {
-                                    second = first;
-                                } else {
-                                    second = rawValue.get(1);
-                                }
-                                convertedList.add(parsePercentOrPx(first, width,viewportW));
-                                convertedList.add(parsePercentOrPx(second, height,viewportW));
-                            }
-
-                            private Float parseCameraDistance(List<String> rawValue){
-                                float ret= Float.MAX_VALUE;
-                                if(rawValue.size() == 1){
-                                    float value = WXViewUtils.getRealPxByWidth(WXUtils.getFloat(rawValue.get(0)), viewportW);
-                                    float scale = WXEnvironment.getApplication().getResources().getDisplayMetrics().density;
-                                    if (!Float.isNaN(value) && value > 0) {
-                                        ret = value * scale;
-                                    }
-                                }
-                                return ret;
-                            }
-                        });
-                return parser.parse();
-            }
-        }catch (Exception e){
-            WXLogUtils.e("TransformParser", e);
-            WXExceptionUtils.commitCriticalExceptionRT(instanceId,
-                    WXErrorCode.WX_RENDER_ERR_TRANSITION,
-                    "parse animation transition",
-                    WXErrorCode.WX_RENDER_ERR_TRANSITION.getErrorMsg() + "parse transition error: " +  e.getMessage(),
-                    null);
-        }
-        return new LinkedHashMap<>();
-    }
-
-    private static Pair<Float, Float> parsePivot(@Nullable String transformOrigin,
-                                                 int width, int height, int viewportW) {
-        if (!TextUtils.isEmpty(transformOrigin)) {
-            int firstSpace = transformOrigin.indexOf(FunctionParser.SPACE);
-            if (firstSpace != -1) {
-                int i = firstSpace;
-                for (; i < transformOrigin.length(); i++) {
-                    if (transformOrigin.charAt(i) != FunctionParser.SPACE) {
-                        break;
-                    }
-                }
-                if (i < transformOrigin.length() && transformOrigin.charAt(i) != FunctionParser.SPACE) {
-                    List<String> list = new ArrayList<>(2);
-                    list.add(transformOrigin.substring(0, firstSpace).trim());
-                    list.add(transformOrigin.substring(i, transformOrigin.length()).trim());
-                    return parsePivot(list, width, height,viewportW);
-                }
-            }
-        }
-        return null;
-    }
-
-    private static Pair<Float, Float> parsePivot(@NonNull List<String> list, int width, int height, int viewportW) {
-        return new Pair<>(
-                parsePivotX(list.get(0), width,viewportW), parsePivotY(list.get(1), height,viewportW));
-    }
-
-    private static float parsePivotX(String x, int width, int viewportW) {
-        String value = x;
-        if (WXAnimationBean.Style.LEFT.equals(x)) {
-            value = ZERO;
-        } else if (WXAnimationBean.Style.RIGHT.equals(x)) {
-            value = FULL;
-        } else if (WXAnimationBean.Style.CENTER.equals(x)) {
-            value = HALF;
-        }
-        return parsePercentOrPx(value, width,viewportW);
-    }
-
-    private static float parsePivotY(String y, int height, int viewportW) {
-        String value = y;
-        if (WXAnimationBean.Style.TOP.equals(y)) {
-            value = ZERO;
-        } else if (WXAnimationBean.Style.BOTTOM.equals(y)) {
-            value = FULL;
-        } else if (WXAnimationBean.Style.CENTER.equals(y)) {
-            value = HALF;
-        }
-        return parsePercentOrPx(value, height,viewportW);
-    }
-
-    private static float parsePercentOrPx(String raw, int unit, int viewportW) {
-        final int precision = 1;
-        int suffix;
-        if ((suffix = raw.lastIndexOf(WXUtils.PERCENT)) != -1) {
-            return parsePercent(raw.substring(0, suffix), unit, precision);
-        } else if ((suffix = raw.lastIndexOf(PX)) != -1) {
-            return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw.substring(0, suffix), precision),viewportW);
-        }
-        return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw, precision),viewportW);
-    }
-
-    private static float parsePercent(String percent, int unit, int precision) {
-        return WXUtils.fastGetFloat(percent, precision) / 100 * unit;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/WXAnimationBean.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/WXAnimationBean.java
deleted file mode 100644
index 4401cb9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/WXAnimationBean.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-import android.animation.PropertyValuesHolder;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import android.util.Pair;
-import android.util.Property;
-import android.view.View;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.Constants.Name;
-import com.taobao.weex.utils.FunctionParser;
-import com.taobao.weex.utils.WXDataStructureUtil;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-public class WXAnimationBean {
-
-  public final static String LINEAR = "linear";
-  public final static String EASE_IN_OUT = "ease-in-out";
-  public final static String EASE_IN = "ease-in";
-  public final static String EASE_OUT = "ease-out";
-  public final static String CUBIC_BEZIER = "cubic-bezier";
-  public final static int NUM_CUBIC_PARAM = 4;
-  public long delay;
-  public long duration;
-  public String timingFunction;
-  public @Nullable Style styles;
-  public boolean needLayout;
-
-  public static class Style {
-
-    public final static String WX_TRANSLATE = "translate";
-    public final static String WX_TRANSLATE_X = "translateX";
-    public final static String WX_TRANSLATE_Y = "translateY";
-    public final static String WX_ROTATE = "rotate";
-    public final static String WX_SCALE_X = "scaleX";
-    public final static String WX_SCALE_Y = "scaleY";
-    public final static String WX_SCALE = "scale";
-    public final static String WX_ROTATE_X ="rotateX";
-    public final static String WX_ROTATE_Y ="rotateY";
-    public final static String BACKGROUND_COLOR = Constants.Name.BACKGROUND_COLOR;
-    public final static String WIDTH = Constants.Name.WIDTH;
-    public final static String HEIGHT = Constants.Name.HEIGHT;
-    public final static String TOP = "top";
-    public final static String BOTTOM = "bottom";
-    public final static String RIGHT = "right";
-    public final static String LEFT = "left";
-    public final static String CENTER = "center";
-    private static final String HALF = "50%";
-    private static final String FULL = "100%";
-    private static final String ZERO = "0%";
-    private static final String PX = "px";
-    private static final String DEG = "deg";
-    public static Map<String, List<Property<View,Float>>> wxToAndroidMap = new ArrayMap<>();
-    private static Map<Property<View, Float>, Float> defaultMap= new ArrayMap<>();
-
-
-    static {
-      wxToAndroidMap.put(WX_TRANSLATE, Arrays.asList
-              (View.TRANSLATION_X, View.TRANSLATION_Y));
-      wxToAndroidMap.put(WX_TRANSLATE_X, Collections.singletonList(View.TRANSLATION_X));
-      wxToAndroidMap.put(WX_TRANSLATE_Y, Collections.singletonList(View.TRANSLATION_Y));
-      wxToAndroidMap.put(WX_ROTATE, Collections.singletonList(View.ROTATION));
-      wxToAndroidMap.put(WX_ROTATE_X, Collections.singletonList(View.ROTATION_X));
-      wxToAndroidMap.put(WX_ROTATE_Y, Collections.singletonList(View.ROTATION_Y));
-      wxToAndroidMap.put(WX_SCALE, Arrays.asList(View.SCALE_X, View.SCALE_Y));
-      wxToAndroidMap.put(WX_SCALE_X, Collections.singletonList(View.SCALE_X));
-      wxToAndroidMap.put(WX_SCALE_Y, Collections.singletonList(View.SCALE_Y));
-      wxToAndroidMap.put(Name.PERSPECTIVE, Collections.singletonList(CameraDistanceProperty.getInstance()));
-      wxToAndroidMap = Collections.unmodifiableMap(wxToAndroidMap);
-      defaultMap.put(View.TRANSLATION_X, 0f);
-      defaultMap.put(View.TRANSLATION_Y, 0f);
-      defaultMap.put(View.SCALE_X, 1f);
-      defaultMap.put(View.SCALE_Y, 1f);
-      defaultMap.put(View.ROTATION, 0f);
-      defaultMap.put(View.ROTATION_X, 0f);
-      defaultMap.put(View.ROTATION_Y, 0f);
-    }
-
-    public String opacity;
-    public String backgroundColor;
-    public String width;
-    public String height;
-    public String transform;
-    public String transformOrigin;
-    private Map<Property<View, Float>, Float> transformMap = new LinkedHashMap<>();
-    private Pair<Float, Float> pivot;
-    private List<PropertyValuesHolder> holders=new LinkedList<>();
-    private float cameraDistance = Float.MAX_VALUE;
-
-
-    private static Pair<Float, Float> parsePivot(@Nullable String transformOrigin,
-                                                 int width, int height,int viewportW) {
-      if (!TextUtils.isEmpty(transformOrigin)) {
-        int firstSpace = transformOrigin.indexOf(FunctionParser.SPACE);
-        if (firstSpace != -1) {
-          int i = firstSpace;
-          for (; i < transformOrigin.length(); i++) {
-            if (transformOrigin.charAt(i) != FunctionParser.SPACE) {
-              break;
-            }
-          }
-          if (i < transformOrigin.length() && transformOrigin.charAt(i) != FunctionParser.SPACE) {
-            List<String> list = new ArrayList<>(2);
-            list.add(transformOrigin.substring(0, firstSpace).trim());
-            list.add(transformOrigin.substring(i, transformOrigin.length()).trim());
-            return parsePivot(list, width, height,viewportW);
-          }
-        }
-      }
-      return null;
-    }
-
-    private static Pair<Float, Float> parsePivot(@NonNull List<String> list, int width, int height,int viewportW) {
-      return new Pair<>(
-              parsePivotX(list.get(0), width,viewportW), parsePivotY(list.get(1), height,viewportW));
-    }
-
-    private static float parsePivotX(String x, int width,int viewportW) {
-      String value = x;
-      if (WXAnimationBean.Style.LEFT.equals(x)) {
-        value = ZERO;
-      } else if (WXAnimationBean.Style.RIGHT.equals(x)) {
-        value = FULL;
-      } else if (WXAnimationBean.Style.CENTER.equals(x)) {
-        value = HALF;
-      }
-      return parsePercentOrPx(value, width,viewportW);
-    }
-
-    private static float parsePivotY(String y, int height,int viewportW) {
-      String value = y;
-      if (WXAnimationBean.Style.TOP.equals(y)) {
-        value = ZERO;
-      } else if (WXAnimationBean.Style.BOTTOM.equals(y)) {
-        value = FULL;
-      } else if (WXAnimationBean.Style.CENTER.equals(y)) {
-        value = HALF;
-      }
-      return parsePercentOrPx(value, height,viewportW);
-    }
-
-    private static float parsePercentOrPx(String raw, int unit,int viewportW) {
-      final int precision = 1;
-      int suffix;
-      if ((suffix = raw.lastIndexOf(WXUtils.PERCENT)) != -1) {
-        return parsePercent(raw.substring(0, suffix), unit, precision);
-      } else if ((suffix = raw.lastIndexOf(PX)) != -1) {
-        return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw.substring(0, suffix), precision),viewportW);
-      }
-      return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw, precision),viewportW);
-    }
-
-    private static float parsePercent(String percent, int unit, int precision) {
-      return WXUtils.fastGetFloat(percent, precision) / 100 * unit;
-    }
-
-    private void resetToDefaultIfAbsent() {
-      for (Entry<Property<View, Float>, Float> entry : defaultMap.entrySet()) {
-        if (!transformMap.containsKey(entry.getKey())) {
-          transformMap.put(entry.getKey(), entry.getValue());
-        }
-      }
-    }
-
-    public @Nullable Pair<Float, Float> getPivot() {
-      return pivot;
-    }
-
-    public void init(@Nullable String transformOrigin,@Nullable String rawTransform,
-                     final int width, final int height,int viewportW, WXSDKInstance instance){
-      pivot = parsePivot(transformOrigin,width,height,viewportW);
-      transformMap.putAll(TransformParser.parseTransForm(instance.getInstanceId(), rawTransform, width,height,viewportW));
-      resetToDefaultIfAbsent();
-      if (transformMap.containsKey(CameraDistanceProperty.getInstance())) {
-        cameraDistance = transformMap.remove(CameraDistanceProperty.getInstance());
-      }
-      initHolders();
-    }
-
-    /**
-     * Use this method to init if you already have a list of Property
-     * The key is something like {@link View#TRANSLATION_X} and the value is a {@link Pair},
-     * of which the first is beginning value and the second is ending value.
-     * @param styles a list of Property
-     */
-    public void init(@NonNull Map<Property<View, Float>, Pair<Float, Float>> styles){
-      for(Entry<Property<View, Float>, Pair<Float, Float>> entry:styles.entrySet()){
-        holders.add(PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue().first, entry.getValue().second));
-      }
-    }
-
-    private void initHolders(){
-      for (Map.Entry<Property<View, Float>, Float> entry : transformMap.entrySet()) {
-        holders.add(PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue()));
-      }
-      if (!TextUtils.isEmpty(opacity)) {
-        holders.add(PropertyValuesHolder.ofFloat(View.ALPHA, WXUtils.fastGetFloat(opacity, 3)));
-      }
-    }
-
-    public List<PropertyValuesHolder> getHolders(){
-      return holders;
-    }
-
-    public float getCameraDistance(){
-      return cameraDistance;
-    }
-  }
-}
-
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/WXAnimationModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/WXAnimationModule.java
deleted file mode 100644
index a614ba3..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/WXAnimationModule.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.ui.action.GraphicActionAnimation;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.list.template.TemplateDom;
-
-public class WXAnimationModule extends WXModule {
-
-  @JSMethod
-  public void transition(@Nullable String ref, @Nullable String animation, @Nullable String callBack) {
-    if (!TextUtils.isEmpty(ref) && !TextUtils.isEmpty(animation) && mWXSDKInstance != null) {
-      //Due to animation module rely on the result of the css-layout and the batch mechanism of
-      //css-layout, the animation.transition must be delayed the batch time.
-      GraphicActionAnimation action = new GraphicActionAnimation(mWXSDKInstance, ref, animation, callBack);
-      WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-    }
-  }
-
-
- 
-
-  //add by moxun on 12/26/2016
-  public static class AnimationHolder {
-
-    private WXAnimationBean wxAnimationBean;
-    private String callback;
-
-    public void execute(WXSDKInstance instance, WXComponent component) {
-      if (null != instance && null != component) {
-        GraphicActionAnimation action = new GraphicActionAnimation(instance, component.getRef(), wxAnimationBean, callback);
-        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
-      }
-    }
-
-    public AnimationHolder(WXAnimationBean wxAnimationBean, String callback) {
-      this.wxAnimationBean = wxAnimationBean;
-      this.callback = callback;
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/animation/WidthProperty.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/WidthProperty.java
deleted file mode 100644
index ca4288f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/animation/WidthProperty.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-
-import android.view.ViewGroup.LayoutParams;
-
-public class WidthProperty extends LayoutParamsProperty {
-
-  @Override
-  protected Integer getProperty(LayoutParams layoutParams) {
-    return layoutParams.width;
-  }
-
-  @Override
-  protected void setProperty(LayoutParams layoutParams, Integer expected) {
-    layoutParams.width = expected;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java
deleted file mode 100644
index 351ac08..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.InputType;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.text.method.DigitsKeyListener;
-import android.text.method.PasswordTransformationMethod;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.dom.CSSConstants;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import com.taobao.weex.layout.MeasureMode;
-import com.taobao.weex.layout.MeasureSize;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.helper.SoftKeyboardDetector;
-import com.taobao.weex.ui.component.helper.WXTimeInputHelper;
-import com.taobao.weex.ui.view.WXEditText;
-import com.taobao.weex.utils.TypefaceUtil;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import static com.taobao.weex.dom.WXStyle.UNSET;
-
-/**
- * Created by sospartan on 7/11/16.
- */
-public abstract class AbstractEditComponent extends WXComponent<WXEditText> {
-
-  private final InputMethodManager mInputMethodManager;
-  private String mBeforeText = "";
-  private boolean mAutoFocus;
-  private String mType = "text";
-  private String mMax = null;
-  private String mMin = null;
-  private String mLastValue = "";
-  private int mEditorAction = EditorInfo.IME_ACTION_DONE;
-  private String mReturnKeyType = null;
-  private List<TextView.OnEditorActionListener> mEditorActionListeners;
-  private boolean mListeningKeyboard = false;
-  private SoftKeyboardDetector.Unregister mUnregister;
-  private boolean mIgnoreNextOnInputEvent = false;
-  private boolean mKeepSelectionIndex = false;
-  private TextFormatter mFormatter = null;
-  private List<TextWatcher> mTextChangedListeners;
-  private TextWatcher mTextChangedEventDispatcher;
-  private int mFormatRepeatCount = 0;
-  private static final int MAX_TEXT_FORMAT_REPEAT = 3;
-
-  private TextPaint mPaint = new TextPaint();
-  private int mLineHeight = UNSET;
-
-  public AbstractEditComponent(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-    super(instance, parent, isLazy, basicComponentData);
-    mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-    setContentBoxMeasurement(new ContentBoxMeasurement() {
-      /** uiThread = false **/
-      @Override
-      public void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode) {
-        if (CSSConstants.isUndefined(width) || widthMeasureMode == MeasureMode.UNSPECIFIED) {
-          width = 0;
-        }
-        mMeasureWidth = width;
-        mMeasureHeight = getMeasureHeight();
-      }
-
-      /** uiThread = false **/
-      @Override
-      public void layoutBefore() {
-        updateStyleAndAttrs();
-      }
-
-      /** uiThread = false **/
-      @Override
-      public void layoutAfter(float computedWidth, float computedHeight) {
-
-      }
-    });
-  }
-
-  @Override
-  protected void layoutDirectionDidChanged(boolean isRTL) {
-    String alignStr = (String) getStyles().get(Constants.Name.TEXT_ALIGN);
-    int textAlign = getTextAlign(alignStr);
-    if (textAlign <= 0) {
-      textAlign = Gravity.START;
-    }
-    if (getHostView() instanceof WXEditText) {
-      getHostView().setGravity(textAlign | getVerticalGravity());
-    }
-  }
-
-  protected final float getMeasuredLineHeight() {
-    return mLineHeight != UNSET && mLineHeight > 0 ? mLineHeight : mPaint.getFontMetrics(null);
-  }
-
-  protected float getMeasureHeight() {
-    return getMeasuredLineHeight();
-  }
-
-  protected void updateStyleAndAttrs() {
-    if (getStyles().size() > 0) {
-      int fontSize = UNSET, fontStyle = UNSET, fontWeight = UNSET;
-      String fontFamily = null;
-      if (getStyles().containsKey(Constants.Name.FONT_SIZE)) {
-        fontSize = WXStyle.getFontSize(getStyles(),getViewPortWidth());
-      }
-
-      if (getStyles().containsKey(Constants.Name.FONT_FAMILY)) {
-        fontFamily = WXStyle.getFontFamily(getStyles());
-      }
-
-      if (getStyles().containsKey(Constants.Name.FONT_STYLE)) {
-        fontStyle = WXStyle.getFontStyle(getStyles());
-      }
-
-      if (getStyles().containsKey(Constants.Name.FONT_WEIGHT)) {
-        fontWeight = WXStyle.getFontWeight(getStyles());
-      }
-
-      int lineHeight = WXStyle.getLineHeight(getStyles(),getViewPortWidth());
-      if (lineHeight != UNSET)
-        mLineHeight = lineHeight;
-
-      if (fontSize != UNSET)
-        mPaint.setTextSize(fontSize);
-
-      if (fontFamily != null) {
-        TypefaceUtil.applyFontStyle(mPaint, fontStyle, fontWeight, fontFamily);
-      }
-    }
-  }
-
-  @Override
-  protected WXEditText initComponentHostView(@NonNull Context context) {
-    final WXEditText inputView = new WXEditText(context);
-    appleStyleAfterCreated(inputView);
-    return inputView;
-  }
-
-  @Override
-  protected void onHostViewInitialized(WXEditText host) {
-    super.onHostViewInitialized(host);
-    addFocusChangeListener(new OnFocusChangeListener() {
-      @Override
-      public void onFocusChange(boolean hasFocus) {
-        if (!hasFocus) {
-          decideSoftKeyboard();
-        }
-        setPseudoClassStatus(Constants.PSEUDO.FOCUS,hasFocus);
-      }
-    });
-
-    addKeyboardListener(host);
-  }
-
-  @Override
-  protected boolean isConsumeTouch() {
-    //EditText always consume touch event except disabled.
-    return !isDisabled();
-  }
-
-  private OnClickListener mOnClickListener = new OnClickListener() {
-    @Override
-    public void onHostViewClick() {
-      switch (mType) {
-        case Constants.Value.DATE:
-          hideSoftKeyboard();
-          if (getParent() != null) {
-            getParent().interceptFocus();
-          }
-          WXTimeInputHelper.pickDate(mMax, mMin, AbstractEditComponent.this);
-          break;
-        case Constants.Value.TIME:
-          hideSoftKeyboard();
-          if (getParent() != null) {
-            getParent().interceptFocus();
-          }
-          WXTimeInputHelper.pickTime(AbstractEditComponent.this);
-          break;
-      }
-    }
-  };
-
-  private void applyOnClickListener() {
-    addClickListener(mOnClickListener);
-  }
-
-
-  protected int getVerticalGravity(){
-    return Gravity.CENTER_VERTICAL;
-  }
-
-  /**
-   * Process view after created.
-   *
-   * @param editText
-   */
-  protected void appleStyleAfterCreated(final WXEditText editText) {
-    String alignStr = (String) getStyles().get(Constants.Name.TEXT_ALIGN);
-    int textAlign = getTextAlign(alignStr);
-    if (textAlign <= 0) {
-      textAlign = Gravity.START;
-    }
-    editText.setGravity(textAlign | getVerticalGravity());
-    final int colorInt = WXResourceUtils.getColor("#999999");
-    if (colorInt != Integer.MIN_VALUE) {
-      editText.setHintTextColor(colorInt);
-    }
-
-    mTextChangedEventDispatcher = new TextWatcher() {
-      @Override
-      public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        if (mTextChangedListeners != null) {
-          for (TextWatcher watcher : mTextChangedListeners) {
-            watcher.beforeTextChanged(s, start, count, after);
-          }
-        }
-      }
-
-      @Override
-      public void onTextChanged(CharSequence s, int start, int before, int count) {
-        if (mFormatter != null) {
-          String raw = mFormatter.recover(s.toString());
-          String result = mFormatter.format(raw);
-          // prevent infinite loop caused by bad format and recover regexp
-          if (!result.equals(s.toString()) && mFormatRepeatCount < MAX_TEXT_FORMAT_REPEAT) {
-            mFormatRepeatCount = mFormatRepeatCount + 1;
-            int index = editText.getSelectionStart();
-            int cursorIndex = mFormatter.format(mFormatter.recover(s.subSequence(0, index).toString())).length();
-            editText.setText(result);
-            editText.setSelection(cursorIndex);
-            return;
-          }
-
-          mFormatRepeatCount = 0;
-        }
-
-        if (mTextChangedListeners != null) {
-          for (TextWatcher watcher : mTextChangedListeners) {
-            watcher.onTextChanged(s, start, before, count);
-          }
-        }
-      }
-
-      @Override
-      public void afterTextChanged(Editable s) {
-        if (mTextChangedListeners != null) {
-          for (TextWatcher watcher : mTextChangedListeners) {
-            watcher.afterTextChanged(s);
-          }
-        }
-      }
-    };
-    editText.addTextChangedListener(mTextChangedEventDispatcher);
-
-    editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, WXStyle.getFontSize(getStyles(), getInstance().getInstanceViewPortWidth()));
-  }
-
-
-  @Override
-  public void addEvent(final String type) {
-    super.addEvent(type);
-    if (getHostView() == null || TextUtils.isEmpty(type)) {
-      return;
-    }
-    final TextView text = getHostView();
-
-    if (type.equals(Constants.Event.CHANGE)) {
-      addFocusChangeListener(new OnFocusChangeListener() {
-        @Override
-        public void onFocusChange(boolean hasFocus) {
-          if (hasFocus) {
-            mLastValue = text.getText().toString();
-          } else {
-            CharSequence newValue = text.getText();
-            newValue = newValue == null ? "" : newValue;
-            if (!newValue.toString().equals(mLastValue)) {
-              fireEvent(Constants.Event.CHANGE, newValue.toString());
-              mLastValue = text.getText().toString();
-            }
-          }
-        }
-      });
-
-      addEditorActionListener(new TextView.OnEditorActionListener() {
-        @Override
-        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-          if (actionId == mEditorAction) {
-            CharSequence newValue = text.getText();
-            newValue = newValue == null ? "" : newValue;
-            if (!newValue.toString().equals(mLastValue)) {
-              fireEvent(Constants.Event.CHANGE, newValue.toString());
-              mLastValue = text.getText().toString();
-            }
-            if (getParent() != null) {
-              getParent().interceptFocus();
-            }
-            hideSoftKeyboard();
-            return true;
-          }
-          return false;
-        }
-      });
-    } else if (type.equals(Constants.Event.INPUT)) {
-      addTextChangedListener(new TextWatcher() {
-        @Override
-        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-
-        }
-
-        @Override
-        public void onTextChanged(CharSequence s, int start, int before, int count) {
-          if (mIgnoreNextOnInputEvent) {
-            mIgnoreNextOnInputEvent = false;
-            mBeforeText = s.toString();
-            return;
-          }
-
-          if (mBeforeText.equals(s.toString())) {
-            return;
-          }
-
-          mBeforeText = s.toString();
-
-          fireEvent(Constants.Event.INPUT, s.toString());
-        }
-
-        @Override
-        public void afterTextChanged(Editable s) {
-
-        }
-      });
-    }
-
-    if (Constants.Event.RETURN.equals(type)) {
-      addEditorActionListener(new TextView.OnEditorActionListener() {
-        @Override
-        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-          if (actionId == mEditorAction) {
-            Map<String, Object> ret = new HashMap<>(2);
-            ret.put("returnKeyType", mReturnKeyType);
-            ret.put("value", v.getText().toString());
-            fireEvent(Constants.Event.RETURN, ret);
-            return true;
-          }
-          return false;
-        }
-      });
-    }
-
-    if (Constants.Event.KEYBOARD.equals(type)) {
-      mListeningKeyboard = true;
-    }
-  }
-
-  private void fireEvent(String event, String value) {
-    if (event != null) {
-      Map<String, Object> params = new HashMap<>(2);
-      params.put("value", value);
-      params.put("timeStamp", System.currentTimeMillis());
-
-      Map<String, Object> domChanges = new HashMap<>();
-      Map<String, Object> attrsChanges = new HashMap<>();
-      attrsChanges.put("value", value);
-      domChanges.put("attrs", attrsChanges);
-
-      WXSDKManager.getInstance().fireEvent(getInstanceId(), getRef(), event, params, domChanges);
-    }
-  }
-
-  public void performOnChange(String value) {
-    if (getEvents() != null) {
-      String event = getEvents().contains(Constants.Event.CHANGE) ? Constants.Event.CHANGE : null;
-      fireEvent(event, value);
-    }
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.DISABLED:
-        Boolean disabled = WXUtils.getBoolean(param, null);
-        if (disabled != null && mHost != null) {
-          if (disabled) {
-            mHost.setFocusable(false);
-            mHost.setFocusableInTouchMode(false);
-          } else {
-            mHost.setFocusableInTouchMode(true);
-            mHost.setFocusable(true);
-          }
-        }
-        return true;
-      case Constants.Name.PLACEHOLDER:
-        String placeholder = WXUtils.getString(param, null);
-        if (placeholder != null)
-          setPlaceholder(placeholder);
-        return true;
-      case Constants.Name.PLACEHOLDER_COLOR:
-        String placeholder_color = WXUtils.getString(param, null);
-        if (placeholder_color != null)
-          setPlaceholderColor(placeholder_color);
-        return true;
-      case Constants.Name.TYPE:
-        String input_type = WXUtils.getString(param, null);
-        if (input_type != null)
-          setType(input_type);
-        return true;
-      case Constants.Name.AUTOFOCUS:
-        Boolean result = WXUtils.getBoolean(param, null);
-        if (result != null)
-          setAutofocus(result);
-        return true;
-      case Constants.Name.COLOR:
-        String color = WXUtils.getString(param, null);
-        if (color != null)
-          setColor(color);
-        return true;
-      case Constants.Name.FONT_SIZE:
-        String fontsize = WXUtils.getString(param, null);
-        if (fontsize != null)
-          setFontSize(fontsize);
-        return true;
-      case Constants.Name.TEXT_ALIGN:
-        String text_align = WXUtils.getString(param, null);
-        if (text_align != null)
-          setTextAlign(text_align);
-        return true;
-      case Constants.Name.SINGLELINE:
-        Boolean singLineResult = WXUtils.getBoolean(param, null);
-        if (singLineResult != null)
-          setSingleLine(singLineResult);
-        return true;
-      case Constants.Name.LINES:
-        Integer lines = WXUtils.getInteger(param, null);
-        if (lines != null)
-          setLines(lines);
-        return true;
-      case Constants.Name.MAX_LENGTH:
-        Integer maxlength = WXUtils.getInteger(param, null);
-        if (maxlength != null)
-          setMaxLength(maxlength);
-        return true;
-      case Constants.Name.MAXLENGTH:
-        Integer maxLength = WXUtils.getInteger(param, null);
-        if (maxLength != null)
-          setMaxLength(maxLength);
-        return true;
-      case Constants.Name.MAX:
-        setMax(String.valueOf(param));
-        return true;
-      case Constants.Name.MIN:
-        setMin(String.valueOf(param));
-        return true;
-      case Constants.Name.RETURN_KEY_TYPE:
-        setReturnKeyType(String.valueOf(param));
-        return true;
-      case Constants.Name.KEEP_SELECTION_INDEX:
-        boolean keepIndex = WXUtils.getBoolean(param, false);
-        mKeepSelectionIndex = keepIndex;
-        return true;
-      case Constants.Name.ALLOW_COPY_PASTE:
-        boolean allowCopyPaste = WXUtils.getBoolean(param, true);
-        if (getHostView() != null) {
-          getHostView().setAllowCopyPaste(allowCopyPaste);
-        }
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @WXComponentProp(name = Constants.Name.RETURN_KEY_TYPE)
-  public void setReturnKeyType(String type) {
-    if (getHostView() == null) {
-      return;
-    }
-    mReturnKeyType = type;
-    switch (type) {
-      case ReturnTypes.DEFAULT:
-        mEditorAction = EditorInfo.IME_ACTION_UNSPECIFIED;
-        break;
-      case ReturnTypes.GO:
-        mEditorAction = EditorInfo.IME_ACTION_GO;
-        break;
-      case ReturnTypes.NEXT:
-        mEditorAction = EditorInfo.IME_ACTION_NEXT;
-        break;
-      case ReturnTypes.SEARCH:
-        mEditorAction = EditorInfo.IME_ACTION_SEARCH;
-        break;
-      case ReturnTypes.SEND:
-        mEditorAction = EditorInfo.IME_ACTION_SEND;
-        break;
-      case ReturnTypes.DONE:
-        mEditorAction = EditorInfo.IME_ACTION_DONE;
-        break;
-      default:
-        break;
-    }
-
-    //remove focus and hide keyboard first, the ImeOptions will take effect when show keyboard next time
-    blur();
-    getHostView().setImeOptions(mEditorAction);
-  }
-
-  @WXComponentProp(name = Constants.Name.PLACEHOLDER)
-  public void setPlaceholder(String placeholder) {
-    if (placeholder == null || getHostView() == null) {
-      return;
-    }
-    ((WXEditText) getHostView()).setHint(placeholder);
-  }
-
-  @WXComponentProp(name = Constants.Name.PLACEHOLDER_COLOR)
-  public void setPlaceholderColor(String color) {
-    if (getHostView() != null && !TextUtils.isEmpty(color)) {
-      int colorInt = WXResourceUtils.getColor(color);
-      if (colorInt != Integer.MIN_VALUE) {
-        ((WXEditText) getHostView()).setHintTextColor(colorInt);
-      }
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.TYPE)
-  public void setType(String type) {
-    Log.e("weex", "setType=" + type);
-    if (type == null || getHostView() == null) {
-      return;
-    }
-    mType = type;
-    ((EditText) getHostView()).setInputType(getInputType(mType));
-    switch (mType) {
-      case Constants.Value.DATE:
-      case Constants.Value.TIME:
-        applyOnClickListener();
-        break;
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.AUTOFOCUS)
-  public void setAutofocus(boolean autofocus) {
-    if (getHostView() == null) {
-      return;
-    }
-    mAutoFocus = autofocus;
-    EditText inputView = getHostView();
-    if (mAutoFocus) {
-      inputView.setFocusable(true);
-      inputView.requestFocus();
-      inputView.setFocusableInTouchMode(true);
-      showSoftKeyboard();
-    } else {
-      hideSoftKeyboard();
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.VALUE)
-  public void setValue(String value) {
-    WXEditText view;
-    if ((view = getHostView()) == null) {
-      return;
-    }
-    if (TextUtils.equals(view.getText(), value)) {
-      return;
-    }
-
-    mIgnoreNextOnInputEvent = true;
-    int oldIndex = view.getSelectionStart();
-    view.setText(value);
-    int index = mKeepSelectionIndex ? oldIndex : value.length();
-    view.setSelection(value == null ? 0 : index);
-  }
-
-  @WXComponentProp(name = Constants.Name.COLOR)
-  public void setColor(String color) {
-    if (getHostView() != null && !TextUtils.isEmpty(color)) {
-      int colorInt = WXResourceUtils.getColor(color);
-      if (colorInt != Integer.MIN_VALUE) {
-        getHostView().setTextColor(colorInt);
-      }
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.FONT_SIZE)
-  public void setFontSize(String fontSize) {
-    if (getHostView() != null && fontSize != null ) {
-      Map<String, Object> map = new HashMap<>(1);
-      map.put(Constants.Name.FONT_SIZE, fontSize);
-      getHostView().setTextSize(TypedValue.COMPLEX_UNIT_PX, WXStyle.getFontSize(map, getInstance().getInstanceViewPortWidth()));
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.TEXT_ALIGN)
-  public void setTextAlign(String textAlign) {
-    int align = getTextAlign(textAlign);
-    if (align > 0) {
-      getHostView().setGravity(align | getVerticalGravity());
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SINGLELINE)
-  public void setSingleLine(boolean singleLine) {
-    if (getHostView() == null) {
-      return;
-    }
-    getHostView().setSingleLine(singleLine);
-  }
-
-  @WXComponentProp(name = Constants.Name.LINES)
-  public void setLines(int lines) {
-    if (getHostView() == null) {
-      return;
-    }
-    getHostView().setLines(lines);
-  }
-
-  /**
-   * Compatible with both 'max-length' and 'maxlength'
-   * @param maxLength
-   */
-  @WXComponentProp(name = Constants.Name.MAX_LENGTH)
-  public void setMaxLength(int maxLength) {
-    if (getHostView() == null) {
-      return;
-    }
-    getHostView().setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
-  }
-
-  /**
-   * Compatible with both 'max-length' and 'maxlength'
-   * @param maxLength
-   */
-  @WXComponentProp(name = Constants.Name.MAXLENGTH)
-  @Deprecated
-  public void setMaxlength(int maxLength) {
-    setMaxLength(maxLength);
-  }
-
-  private int getInputType(String type) {
-    int inputType;
-    switch (type) {
-      case Constants.Value.TEXT:
-        inputType = InputType.TYPE_CLASS_TEXT;
-        break;
-      case Constants.Value.DATE:
-        inputType = InputType.TYPE_NULL;
-        getHostView().setFocusable(false);
-        break;
-      case Constants.Value.DATETIME:
-        inputType = InputType.TYPE_CLASS_DATETIME;
-        break;
-      case Constants.Value.EMAIL:
-        inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
-        break;
-      case Constants.Value.PASSWORD:
-        inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;
-        if(getHostView() != null){
-            getHostView().setTransformationMethod(PasswordTransformationMethod.getInstance());
-        }
-        break;
-      case Constants.Value.TEL:
-        inputType = InputType.TYPE_CLASS_PHONE;
-        break;
-      case Constants.Value.TIME:
-        inputType = InputType.TYPE_NULL;
-        if(getHostView() != null){
-            getHostView().setFocusable(false);
-        }
-        break;
-      case Constants.Value.URL:
-        inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
-        break;
-      case Constants.Value.NUMBER:
-        inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL;
-        break;
-      default:
-        inputType = InputType.TYPE_CLASS_TEXT;
-    }
-    return inputType;
-  }
-
-  @WXComponentProp(name = Constants.Name.MAX)
-  public void setMax(String max) {
-    mMax = max;
-  }
-
-  @WXComponentProp(name = Constants.Name.MIN)
-  public void setMin(String min) {
-    mMin = min;
-  }
-
-  private boolean showSoftKeyboard() {
-    if (getHostView() == null) {
-      return false;
-    } else {
-      getHostView().postDelayed(WXThread.secure(new Runnable() {
-        @Override
-        public void run() {
-          if (getInstance() != null && getInstance().getApmForInstance() != null){
-            getInstance().getApmForInstance().forceStopRecordInteraction = true;
-          }
-          mInputMethodManager.showSoftInput(getHostView(), InputMethodManager.SHOW_IMPLICIT);
-        }
-      }), 100);
-    }
-    return true;
-  }
-
-  private void hideSoftKeyboard() {
-    if (getHostView() != null) {
-      getHostView().postDelayed(WXThread.secure(new Runnable() {
-        @Override
-        public void run() {
-          mInputMethodManager.hideSoftInputFromWindow(getHostView().getWindowToken(), 0);
-        }
-      }), 16);
-    }
-  }
-
-  private int getTextAlign(String textAlign) {
-    boolean isRTL = isLayoutRTL();
-    int align = isRTL ? Gravity.END : Gravity.START;
-    if (TextUtils.isEmpty(textAlign)) {
-      return align;
-    }
-
-    if (textAlign.equals(Constants.Value.LEFT)) {
-      align = Gravity.START;
-    } else if (textAlign.equals(Constants.Value.CENTER)) {
-      align = Gravity.CENTER;
-    } else if (textAlign.equals(Constants.Value.RIGHT)) {
-      align = Gravity.END;
-    }
-    return align;
-  }
-
-  @JSMethod
-  public void blur() {
-    WXEditText host = getHostView();
-    if (host != null && host.hasFocus()) {
-      if (getParent() != null) {
-        getParent().interceptFocus();
-      }
-      host.clearFocus();
-      hideSoftKeyboard();
-    }
-  }
-
-  @JSMethod
-  public void focus() {
-    WXEditText host = getHostView();
-    if (host != null && !host.hasFocus()) {
-      if (getParent() != null) {
-        getParent().ignoreFocus();
-      }
-      host.requestFocus();
-      host.setFocusable(true);
-      host.setFocusableInTouchMode(true);
-      showSoftKeyboard();
-    }
-  }
-
-  @Override
-  protected Object convertEmptyProperty(String propName, Object originalValue) {
-    switch (propName) {
-      case Constants.Name.FONT_SIZE:
-        return WXText.sDEFAULT_SIZE;
-      case Constants.Name.COLOR:
-        return "black";
-    }
-    return super.convertEmptyProperty(propName, originalValue);
-  }
-
-  private void decideSoftKeyboard() {
-    View hostView;
-    if ((hostView = getHostView()) != null) {
-      final Context context = getContext();
-      if (context != null && context instanceof Activity) {
-        hostView.postDelayed(WXThread.secure(new Runnable() {
-          @Override
-          public void run() {
-            View currentFocus = ((Activity) context).getCurrentFocus();
-            if (!(currentFocus instanceof EditText)) {
-              mInputMethodManager.hideSoftInputFromWindow(getHostView().getWindowToken(), 0);
-            }
-          }
-        }), 16);
-      }
-    }
-  }
-
-  @JSMethod
-  public void setSelectionRange(int selectionStart, int selectionEnd) {
-    EditText hostView;
-    if ((hostView = getHostView()) != null) {
-      int length = getHostView().length();
-      if (selectionStart > length || selectionEnd > length) {
-        return;
-      }
-      focus();
-      hostView.setSelection(selectionStart, selectionEnd);
-    }
-  }
-
-  @JSMethod
-  public void getSelectionRange(String callbackId) {
-    EditText hostView;
-    Map<String, Object> result = new HashMap<>(2);
-    if ((hostView = getHostView()) != null) {
-      int start = hostView.getSelectionStart();
-      int end = hostView.getSelectionEnd();
-
-      if (!hostView.hasFocus()) {
-        //The default behavior, same as iOS and web
-        start = 0;
-        end = 0;
-      }
-
-      result.put(Constants.Name.SELECTION_START, start);
-      result.put(Constants.Name.SELECTION_END, end);
-    }
-    WXBridgeManager.getInstance().callback(getInstanceId(), callbackId, result, false);
-  }
-
-  @JSMethod
-  public void setTextFormatter(JSONObject params) {
-    try {
-      String formatRule = params.getString("formatRule");
-      String formatReplace = params.getString("formatReplace");
-      String recoverRule = params.getString("recoverRule");
-      String recoverReplace = params.getString("recoverReplace");
-
-      PatternWrapper format = parseToPattern(formatRule, formatReplace);
-      PatternWrapper recover = parseToPattern(recoverRule, recoverReplace);
-
-      if (format != null && recover != null) {
-        mFormatter = new TextFormatter(format, recover);
-      }
-    } catch (Throwable t) {
-      t.printStackTrace();
-    }
-  }
-
-  protected final void addEditorActionListener(TextView.OnEditorActionListener listener) {
-    TextView view;
-    if (listener != null && (view = getHostView()) != null) {
-      if (mEditorActionListeners == null) {
-        mEditorActionListeners = new ArrayList<>();
-        view.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-          private boolean handled = true;
-
-          @Override
-          public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-            for (TextView.OnEditorActionListener l : mEditorActionListeners) {
-              if (l != null) {
-                handled = handled & l.onEditorAction(v, actionId, event);
-              }
-            }
-            return handled;
-          }
-        });
-      }
-      mEditorActionListeners.add(listener);
-    }
-  }
-
-  public final void addTextChangedListener(TextWatcher watcher) {
-    if (mTextChangedListeners == null) {
-      mTextChangedListeners = new ArrayList<>();
-    }
-    mTextChangedListeners.add(watcher);
-  }
-
-  private void addKeyboardListener(final WXEditText host) {
-    if (host == null) {
-      return;
-    }
-    final Context context = host.getContext();
-    if (context != null && context instanceof Activity) {
-      SoftKeyboardDetector.registerKeyboardEventListener((Activity) context, new SoftKeyboardDetector.OnKeyboardEventListener() {
-        @Override
-        public void onKeyboardEvent(boolean isShown) {
-          if (mListeningKeyboard) {
-            Map<String, Object> event = new HashMap<>(1);
-            event.put("isShow", isShown);
-            if (isShown) {
-              Rect r = new Rect();
-              ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
-              float keyboardSize = WXViewUtils.getWebPxByWidth(WXViewUtils.getScreenHeight(context) - (r.bottom - r.top),
-                      getInstance().getInstanceViewPortWidth());
-              event.put("keyboardSize", keyboardSize);
-            }
-            fireEvent(Constants.Event.KEYBOARD, event);
-          }
-          if (!isShown) {
-            blur();
-          }
-        }
-      });
-    }
-  }
-
-  @Override
-  public void destroy() {
-    super.destroy();
-    if (mUnregister != null) {
-      try {
-        mUnregister.execute();
-        mUnregister = null;
-      } catch (Throwable throwable) {
-        WXLogUtils.w("Unregister throw ", throwable);
-      }
-    }
-  }
-
-  private PatternWrapper parseToPattern(String jsPattern, String replace) {
-    if (jsPattern == null || replace == null) {
-      return null;
-    }
-
-    String checker = "/[\\S]+/[i]?[m]?[g]?";
-    if (!Pattern.compile(checker).matcher(jsPattern).matches()) {
-      WXLogUtils.w("WXInput", "Illegal js pattern syntax: " + jsPattern);
-      return null;
-    }
-
-    int flags = 0;
-    boolean global = false;
-    String flagsStr = jsPattern.substring(jsPattern.lastIndexOf("/") + 1);
-    String regExp = jsPattern.substring(jsPattern.indexOf("/") + 1, jsPattern.lastIndexOf("/"));
-
-    if (flagsStr.contains("i")) {
-      flags |= Pattern.CASE_INSENSITIVE;
-    }
-
-    if (flagsStr.contains("m")) {
-      flags |= Pattern.DOTALL;
-    }
-
-    if (flagsStr.contains("g")) {
-      global = true;
-    }
-
-    Pattern pattern = null;
-    try {
-      pattern = Pattern.compile(regExp, flags);
-    } catch (PatternSyntaxException e) {
-      WXLogUtils.w("WXInput", "Pattern syntax error: " + regExp);
-    }
-    if (pattern == null) {
-      return null;
-    }
-
-    PatternWrapper wrapper = new PatternWrapper();
-    wrapper.global = global;
-    wrapper.matcher = pattern;
-    wrapper.replace = replace;
-    return wrapper;
-  }
-
-  private interface ReturnTypes {
-    String DEFAULT = "default";
-    String GO = "go";
-    String NEXT = "next";
-    String SEARCH = "search";
-    String SEND = "send";
-    String DONE = "done";
-  }
-
-  private static class PatternWrapper {
-    private boolean global = false;
-    private Pattern matcher;
-    private String replace;
-  }
-
-  private static class TextFormatter {
-    private PatternWrapper format;
-    private PatternWrapper recover;
-
-    private TextFormatter(PatternWrapper format, PatternWrapper recover) {
-      this.format = format;
-      this.recover = recover;
-    }
-
-    private String format(String src) {
-      try {
-        if (format != null) {
-          if (format.global) {
-            return format.matcher.matcher(src).replaceAll(format.replace);
-          } else {
-            return format.matcher.matcher(src).replaceFirst(format.replace);
-          }
-        }
-      } catch (Throwable t) {
-        //maybe IndexOutOfBoundsException caused by illegal replace
-        WXLogUtils.w("WXInput", "[format] " + t.getMessage());
-      }
-      return src;
-    }
-
-    private String recover(String formatted) {
-      try {
-        if (recover != null) {
-          if (recover.global) {
-            return recover.matcher.matcher(formatted).replaceAll(recover.replace);
-          } else {
-            return recover.matcher.matcher(formatted).replaceFirst(recover.replace);
-          }
-        }
-      } catch (Throwable t) {
-        //same cause as format
-        WXLogUtils.w("WXInput", "[formatted] " + t.getMessage());
-      }
-      return formatted;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/AppearanceHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/AppearanceHelper.java
deleted file mode 100644
index 4481be8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/AppearanceHelper.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.graphics.Rect;
-import android.view.View;
-import com.taobao.weex.utils.WXLogUtils;
-
-
-/**
- * Created by sospartan on 8/19/16.
- */
-public class AppearanceHelper {
-
-  private final WXComponent mAwareChild;
-
-  private boolean mAppearStatus = false;
-  private boolean[] mWatchFlags = {false, false};
-
-  public static final int APPEAR = 0;
-  public static final int DISAPPEAR = 1;
-
-  public static final int RESULT_APPEAR = 1;
-  public static final int RESULT_DISAPPEAR = -1;
-  public static final int RESULT_NO_CHANGE = 0;
-
-  private Rect mVisibleRect = new Rect();
-
-  private int mCellPositionInScrollable;
-
-  /**
-   * @param awareChild child to notify when appearance changed.
-   */
-  public AppearanceHelper(WXComponent awareChild) {
-    this(awareChild, 0);
-  }
-
-  public AppearanceHelper(WXComponent awareChild, int cellPositionInScrollable) {
-    mAwareChild = awareChild;
-    mCellPositionInScrollable = cellPositionInScrollable;
-  }
-
-  public void setCellPosition(int pos){
-    mCellPositionInScrollable = pos;
-  }
-
-  public int getCellPositionINScollable() {
-    return mCellPositionInScrollable;
-  }
-
-  /**
-   * @param event  {@link #APPEAR} and {@link #DISAPPEAR}
-   * @param enable
-   */
-  public void setWatchEvent(int event, boolean enable) {
-    mWatchFlags[event] = enable;
-  }
-
-  /**
-   * @return
-   */
-  public boolean isWatch() {
-    return mWatchFlags[APPEAR] || mWatchFlags[DISAPPEAR];
-  }
-
-
-  public WXComponent getAwareChild() {
-    return mAwareChild;
-  }
-
-  public boolean isAppear() {
-    return mAppearStatus;
-  }
-
-  public int setAppearStatus(boolean newIsAppear) {
-    if (mAppearStatus != newIsAppear) {
-      mAppearStatus = newIsAppear;
-      return newIsAppear ? RESULT_APPEAR : RESULT_DISAPPEAR;
-    }
-
-    return RESULT_NO_CHANGE;
-  }
-
-  public boolean isViewVisible(boolean isList) {
-    View view = mAwareChild.getHostView();
-    if(isList){
-      if(view.getVisibility() == View.VISIBLE){
-        if(view.getMeasuredHeight()  == 0){
-          return  true;
-        }
-      }
-    }
-    return view != null && view.getLocalVisibleRect(mVisibleRect);
-
-  }
-
-  public boolean isViewVisible(View view) {
-    if(view.getVisibility() == View.VISIBLE){
-      if(view.getMeasuredHeight()  == 0){
-        return  true;
-      }
-    }
-    return view != null && view.getLocalVisibleRect(mVisibleRect);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/NestedContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/NestedContainer.java
deleted file mode 100644
index 0451502..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/NestedContainer.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.view.ViewGroup;
-import com.taobao.weex.WXSDKInstance;
-
-/**
- * Created by sospartan on 8/24/16.
- */
-public interface NestedContainer {
-  void setOnNestEventListener(OnNestedInstanceEventListener listener);
-
-  ViewGroup getViewContainer();
-
-  void renderNewURL(String url);
-
-  void reload();
-
-  interface OnNestedInstanceEventListener {
-    void onException(NestedContainer comp, String errCode, String msg);
-
-    /**
-     *
-     * @param comp
-     * @param src
-     * @return true if keep load
-     */
-    boolean onPreCreate(NestedContainer comp, String src);
-
-    String transformUrl(String origin);
-
-    void onCreated(NestedContainer comp, WXSDKInstance nestedInstance);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/Scrollable.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/Scrollable.java
deleted file mode 100644
index 1094bd1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/Scrollable.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.view.ViewGroup;
-
-import java.util.Map;
-
-/**
- * Created by sospartan on 7/5/16.
- */
-public interface Scrollable {
-
-  void bindStickStyle(WXComponent component);
-
-  void unbindStickStyle(WXComponent component);
-
-  void bindAppearEvent(WXComponent component);
-
-  void bindDisappearEvent(WXComponent component);
-
-  void unbindAppearEvent(WXComponent component);
-
-  void unbindDisappearEvent(WXComponent component);
-
-  ViewGroup getView();
-
-  void scrollTo(WXComponent component, Map<String, Object> options);
-
-  String getRef();
-
-  int getScrollY();
-
-  int getScrollX();
-
-  /**
-   *
-   * @return {@link com.taobao.weex.common.Constants.Orientation#HORIZONTAL} or {@link com.taobao.weex.common.Constants.Orientation#VERTICAL}
-   */
-  int getOrientation();
-
-  boolean isScrollable();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/Textarea.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/Textarea.java
deleted file mode 100644
index acc9100..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/Textarea.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.text.TextUtils;
-import android.view.Gravity;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXEditText;
-import com.taobao.weex.utils.WXUtils;
-
-/**
- * Created by sospartan on 7/11/16.
- */
-public class Textarea extends AbstractEditComponent {
-
-  public static final int DEFAULT_ROWS = 2;
-  private int mNumberOfLines = DEFAULT_ROWS;
-
-  public Textarea(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-    super(instance, parent, isLazy, basicComponentData);
-  }
-
-  @Override
-  protected void onHostViewInitialized(WXEditText host) {
-    host.setAllowDisableMovement(false);
-    super.onHostViewInitialized(host);
-  }
-
-  @Override
-  protected void appleStyleAfterCreated(WXEditText editText) {
-    super.appleStyleAfterCreated(editText);
-    String rowsStr = (String) getStyles().get(Constants.Name.ROWS);
-
-    int rows = DEFAULT_ROWS;
-    try{
-      if(!TextUtils.isEmpty(rowsStr)) {
-        rows = Integer.parseInt(rowsStr);
-      }
-    }catch (NumberFormatException e){
-      //ignore
-      e.printStackTrace();
-    }
-
-    editText.setLines(rows);
-    editText.setMinLines(rows);
-  }
-
-  @Override
-  protected int getVerticalGravity() {
-    return Gravity.TOP;
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.ROWS:
-        Integer rows = WXUtils.getInteger(param,null);
-        if (rows != null)
-          setRows(rows);
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @WXComponentProp(name = Constants.Name.ROWS)
-  public void setRows(int rows){
-    WXEditText text = getHostView();
-    if(text == null||rows <=0 ){
-      return;
-    }
-
-    text.setLines(rows);
-  }
-
-  @Override
-  protected float getMeasureHeight(){
-    return getMeasuredLineHeight() * mNumberOfLines;
-  }
-
-  @Override
-  protected void updateStyleAndAttrs() {
-    super.updateStyleAndAttrs();
-    Object raw = getAttrs().get(Constants.Name.ROWS);
-    if (raw == null) {
-      return;
-    } else if (raw instanceof String) {
-      String rowsStr = (String) raw;
-      try {
-        int lines = Integer.parseInt(rowsStr);
-        if (lines > 0) {
-          mNumberOfLines = lines;
-        }
-      } catch (NumberFormatException e) {
-        e.printStackTrace();
-      }
-    } else if (raw instanceof Integer) {
-      mNumberOfLines = (Integer) raw;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXA.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXA.java
deleted file mode 100644
index e0b8442..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXA.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXFrameLayout;
-import com.taobao.weex.utils.ATagUtil;
-
-@Component(lazyload = false)
-public class WXA extends WXDiv {
-
-  @Deprecated
-  public WXA(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXA(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  @Override
-  protected void onHostViewInitialized(WXFrameLayout host) {
-    addClickListener(new OnClickListener() {
-      @Override
-      public void onHostViewClick() {
-        String href;
-        WXAttr attr = getAttrs();
-        if (attr !=null && (href = (String)attr.get("href")) != null) {
-          ATagUtil.onClick(null, getInstanceId(), href);
-        }
-      }
-    });
-    super.onHostViewInitialized(host);
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch(key){
-      case Constants.Name.HREF:
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXBaseRefresh.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXBaseRefresh.java
deleted file mode 100644
index 45a21e8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXBaseRefresh.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXFrameLayout;
-
-/**
- * div component
- */
-@Component(lazyload = false)
-
-public class WXBaseRefresh extends WXVContainer<WXFrameLayout> {
-
-  private WXLoadingIndicator mLoadingIndicator;
-
-  public WXBaseRefresh(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
-    super(instance, parent, lazy, basicComponentData);
-  }
-
-  @Override
-  public void addChild(WXComponent child) {
-    super.addChild(child);
-    this.checkLoadingIndicator(child);
-  }
-
-  @Override
-  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
-    return new WXFrameLayout(context);
-  }
-
-  @Override
-  public void addChild(WXComponent child, int index) {
-    super.addChild(child, index);
-    this.checkLoadingIndicator(child);
-  }
-
-  private void checkLoadingIndicator(WXComponent child) {
-    if (child instanceof WXLoadingIndicator) {
-      mLoadingIndicator = (WXLoadingIndicator) child;
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXBasicComponentType.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXBasicComponentType.java
deleted file mode 100644
index 936206f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXBasicComponentType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-/**
- * basic Component types
- */
-public class WXBasicComponentType {
-
-  public static final String TEXT = "text";
-  public static final String IMAGE = "image";
-  public static final String IMG = "img";
-  public static final String CONTAINER = "container";
-  public static final String DIV = "div";
-  public static final String SCROLLER = "scroller";
-  public static final String SLIDER = "slider";
-  public static final String SLIDER_NEIGHBOR = "slider-neighbor";
-  public static final String LIST = "list";
-  public static final String RECYCLER = "recycler";
-  public static final String WATERFALL = "waterfall";
-  public static final String VLIST = "vlist";
-  public static final String HLIST = "hlist";
-  public static final String CELL = "cell";
-  public static final String HEADER = "header";
-  public static final String FOOTER = "footer";
-  public static final String INDICATOR = "indicator";
-  public static final String VIDEO = "video";
-  public static final String INPUT = "input";
-  public static final String TEXTAREA = "textarea";
-  public static final String SWITCH = "switch";
-  public static final String A = "a";
-  public static final String EMBED = "embed";
-  public static final String WEB = "web";
-  public static final String REFRESH = "refresh";
-  public static final String LOADING = "loading";
-  public static final String LOADING_INDICATOR = "loading-indicator";
-  public static final String CYCLE_SLIDER = "cycleslider";
-  public static final String RICHTEXT = "richtext";
-
-  public static final String RECYCLE_LIST = "recycle-list";
-  public static final String CELL_SLOT = "cell-slot";
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
deleted file mode 100644
index 17630e1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
+++ /dev/null
@@ -1,2467 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Path;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.RippleDrawable;
-import android.os.Build;
-import android.support.annotation.CallSuper;
-import android.support.annotation.CheckResult;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.text.TextUtils;
-import android.util.Pair;
-import android.view.Gravity;
-import android.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOverlay;
-import android.widget.FrameLayout;
-import com.alibaba.fastjson.JSONArray;
-import com.taobao.weex.ComponentObserver;
-import com.taobao.weex.IWXActivityStateListener;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXAccessibilityRoleAdapter;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.bridge.EventResult;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.IWXObject;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXPerformance;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.dom.CSSShorthand.CORNER;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.dom.transition.WXTransition;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import com.taobao.weex.performance.WXAnalyzerDataTransfer;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.tracing.Stopwatch;
-import com.taobao.weex.tracing.WXTracing;
-import com.taobao.weex.ui.IFComponentHolder;
-import com.taobao.weex.ui.WXRenderManager;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.action.GraphicActionAnimation;
-import com.taobao.weex.ui.action.GraphicActionUpdateStyle;
-import com.taobao.weex.ui.action.GraphicPosition;
-import com.taobao.weex.ui.action.GraphicSize;
-import com.taobao.weex.ui.animation.WXAnimationBean;
-import com.taobao.weex.ui.animation.WXAnimationModule;
-import com.taobao.weex.ui.component.basic.WXBasicComponent;
-import com.taobao.weex.ui.component.binding.Statements;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
-import com.taobao.weex.ui.component.pesudo.OnActivePseudoListner;
-import com.taobao.weex.ui.component.pesudo.PesudoStatus;
-import com.taobao.weex.ui.component.pesudo.TouchActivePseudoListener;
-import com.taobao.weex.ui.flat.FlatComponent;
-import com.taobao.weex.ui.flat.FlatGUIContext;
-import com.taobao.weex.ui.flat.WidgetContainer;
-import com.taobao.weex.ui.flat.widget.AndroidViewWidget;
-import com.taobao.weex.ui.flat.widget.Widget;
-import com.taobao.weex.ui.view.border.BorderDrawable;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.ui.view.gesture.WXGestureType;
-import com.taobao.weex.utils.BoxShadowUtil;
-import com.taobao.weex.utils.WXDataStructureUtil;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXReflectionUtils;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * abstract component
- */
-public abstract class WXComponent<T extends View> extends WXBasicComponent implements IWXObject, IWXActivityStateListener, OnActivePseudoListner {
-
-  public static final String PROP_FIXED_SIZE = "fixedSize";
-  public static final String PROP_FS_MATCH_PARENT = "m";
-  public static final String PROP_FS_WRAP_CONTENT = "w";
-  public static final String TYPE = "type";
-  public static final String ROOT = "_root";
-
-  private int mFixedProp = 0;
-  /** package **/ T mHost;
-
-  private volatile WXVContainer mParent;
-  private WXSDKInstance mInstance;
-  private Context mContext;
-
-  private int mAbsoluteY = 0;
-  private int mAbsoluteX = 0;
-  private boolean isLastLayoutDirectionRTL = false;
-  @Nullable
-  private Set<String> mGestureType;
-
-  private BorderDrawable mBackgroundDrawable;
-  private Drawable mRippleBackground;
-  private int mPreRealWidth = 0;
-  private int mPreRealHeight = 0;
-  private int mPreRealLeft = 0;
-  private int mPreRealRight = 0;
-  private int mPreRealTop = 0;
-  private int mStickyOffset = 0;
-  protected WXGesture mGesture;
-  private IFComponentHolder mHolder;
-  private boolean isUsing = false;
-  private List<OnClickListener> mHostClickListeners;
-  private List<OnFocusChangeListener> mFocusChangeListeners;
-  private Set<String> mAppendEvents;
-  private WXAnimationModule.AnimationHolder mAnimationHolder;
-  private PesudoStatus mPesudoStatus;
-  private boolean mIsDestroyed = false;
-  private boolean mIsDisabled = false;
-  private int mType = TYPE_COMMON;
-  private boolean mNeedLayoutOnAnimation = false;
-  private String mLastBoxShadowId;
-  public int mDeepInComponentTree = 0;
-  public boolean mIsAddElementToTree = false;
-  //for fix element case
-  public int interactionAbsoluteX=0,interactionAbsoluteY=0;
-  //for fix slider case :cssLeft is not real left base parent;
-  protected int mChildrensWidth = 0;
-  private boolean mHasAddFocusListener = false;
-
-  public WXTracing.TraceInfo mTraceInfo = new WXTracing.TraceInfo();
-
-  public static final int TYPE_COMMON = 0;
-  public static final int TYPE_VIRTUAL = 1;
-
-  private boolean waste = false;
-  public boolean isIgnoreInteraction = false;
-
-  protected ContentBoxMeasurement contentBoxMeasurement;
-  private WXTransition mTransition;
-  private GraphicSize mPseudoResetGraphicSize;
-  @Nullable
-  private ConcurrentLinkedQueue<Pair<String, Map<String, Object>>> animations;
-
-  @Deprecated
-  public WXComponent(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  @Deprecated
-  public WXComponent(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXComponent(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    this(instance, parent, TYPE_COMMON, basicComponentData);
-  }
-
-  public WXComponent(WXSDKInstance instance, WXVContainer parent, int type, BasicComponentData basicComponentData) {
-    super(basicComponentData);
-    mInstance = instance;
-    mContext = mInstance.getContext();
-    mParent = parent;
-    mType = type;
-
-    if (instance != null)
-      setViewPortWidth(instance.getInstanceViewPortWidth());
-
-    onCreate();
-    ComponentObserver observer;
-    if ((observer = getInstance().getComponentObserver()) != null) {
-      observer.onCreate(this);
-    }
-  }
-
-
-
-  @Override
-  protected final void bindComponent(WXComponent component) {
-    super.bindComponent(component);
-    if (getInstance() != null) {
-      setViewPortWidth(getInstance().getInstanceViewPortWidth());
-    }
-    mParent = component.getParent();
-    mType = component.getType();
-  }
-
-  protected final void setContentBoxMeasurement(final ContentBoxMeasurement contentBoxMeasurement) {
-    this.contentBoxMeasurement = contentBoxMeasurement;
-    mInstance.addContentBoxMeasurement(getRenderObjectPtr(), contentBoxMeasurement);
-    WXBridgeManager.getInstance().bindMeasurementToRenderObject(getRenderObjectPtr());
-  }
-
-
-  @SuppressLint("RtlHardcoded")
-  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
-      lp.setMargins(left, top, right, bottom);
-      if (lp instanceof FrameLayout.LayoutParams) {
-          FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
-          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
-      }
-  }
-
-  public void updateStyles(WXComponent component) {
-    if (component != null) {
-      updateProperties(component.getStyles());
-      applyBorder(component);
-    }
-  }
-
-  public void updateStyles(Map<String, Object> styles) {
-    if (styles != null) {
-      updateProperties(styles);
-      applyBorder(this);
-    }
-  }
-
-  public void updateAttrs(WXComponent component) {
-    if (component != null) {
-      updateProperties(component.getAttrs());
-    }
-  }
-
-  public void updateAttrs(Map<String, Object> attrs) {
-    if (attrs != null) {
-      updateProperties(attrs);
-    }
-  }
-
-  private void applyBorder(WXComponent component) {
-    CSSShorthand border = component.getBorder();
-    float left = border.get(CSSShorthand.EDGE.LEFT);
-    float top = border.get(CSSShorthand.EDGE.TOP);
-    float right = border.get(CSSShorthand.EDGE.RIGHT);
-    float bottom = border.get(CSSShorthand.EDGE.BOTTOM);
-
-    if (mHost == null) {
-      return;
-    }
-
-    setBorderWidth(Constants.Name.BORDER_LEFT_WIDTH, left);
-    setBorderWidth(Constants.Name.BORDER_TOP_WIDTH, top);
-    setBorderWidth(Constants.Name.BORDER_RIGHT_WIDTH, right);
-    setBorderWidth(Constants.Name.BORDER_BOTTOM_WIDTH, bottom);
-  }
-
-  public void setPadding(CSSShorthand padding, CSSShorthand border) {
-    int left = (int) (padding.get(CSSShorthand.EDGE.LEFT) + border.get(CSSShorthand.EDGE.LEFT));
-    int top = (int) (padding.get(CSSShorthand.EDGE.TOP) + border.get(CSSShorthand.EDGE.TOP));
-    int right = (int) (padding.get(CSSShorthand.EDGE.RIGHT) + border.get(CSSShorthand.EDGE.RIGHT));
-    int bottom = (int) (padding.get(CSSShorthand.EDGE.BOTTOM) + border.get(CSSShorthand.EDGE.BOTTOM));
-
-    if (this instanceof FlatComponent && !((FlatComponent) this).promoteToView(true)) {
-      ((FlatComponent) this).getOrCreateFlatWidget().setContentBox(left, top, right, bottom);
-    } else if (mHost != null) {
-      mHost.setPadding(left, top, right, bottom);
-    }
-  }
-
-
-  public void applyComponentEvents(){
-       applyEvents();
-  }
-
-  private void applyEvents() {
-    if (getEvents() == null || getEvents().isEmpty())
-      return;
-    WXEvent event = getEvents();
-    int size = event.size();
-    for (int i=0; i<size; i++) {
-      if(i >= event.size()){
-        break;
-      }
-      String type = event.get(i);
-      addEvent(type);
-    }
-    setActiveTouchListener();
-  }
-
-  /**
-   * Do not use this method to add event, this only apply event already add to DomObject.
-   *
-   * @param type
-   */
-  public void addEvent(final String type) {
-    if (mAppendEvents == null) {
-      mAppendEvents = new HashSet<>();
-    }
-    if (TextUtils.isEmpty(type) || mAppendEvents.contains(type)) {
-      return;
-    }
-    final View view = getRealView();
-
-    if (type.equals(Constants.Event.LAYEROVERFLOW))
-      addLayerOverFlowListener(getRef());
-
-    if (type.equals(Constants.Event.CLICK)) {
-      if (view == null) {
-        // wait next time to add.
-        return;
-      }
-      if(mClickEventListener == null){
-        mClickEventListener = new OnClickListenerImp();
-      }
-      addClickListener(mClickEventListener);
-    } else if ((type.equals(Constants.Event.FOCUS) || type.equals(Constants.Event.BLUR))) {
-      if (!mHasAddFocusListener){
-        mHasAddFocusListener = true;
-        addFocusChangeListener(new OnFocusChangeListener() {
-        @Override
-        public void onFocusChange(boolean hasFocus) {
-          Map<String, Object> params = new HashMap<>();
-          params.put("timeStamp", System.currentTimeMillis());
-          fireEvent(hasFocus ? Constants.Event.FOCUS : Constants.Event.BLUR, params);
-        }
-      });
-      }
-    } else if (needGestureDetector(type)) {
-      if (null == view) {
-        // wait next time to add.
-        return;
-      }
-      if (view instanceof WXGestureObservable) {
-        if (mGesture == null) {
-          mGesture = new WXGesture(this, mContext);
-          boolean isPreventMove = WXUtils.getBoolean(getAttrs().get(Constants.Name.PREVENT_MOVE_EVENT), false);
-          mGesture.setPreventMoveEvent(isPreventMove);
-        }
-        if (mGestureType == null) {
-          mGestureType = new HashSet<>();
-        }
-        mGestureType.add(type);
-        ((WXGestureObservable)view).registerGestureListener(mGesture);
-      } else {
-        WXLogUtils.e(view.getClass().getSimpleName() + " don't implement " +
-            "WXGestureObservable, so no gesture is supported.");
-      }
-    } else {
-      final Scrollable scroller = getParentScroller();
-      if (scroller == null) {
-        // wait next time to add.
-        return;
-      }
-      if (type.equals(Constants.Event.APPEAR)) {
-        scroller.bindAppearEvent(this);
-      } else if (type.equals(Constants.Event.DISAPPEAR)) {
-        scroller.bindDisappearEvent(this);
-      }
-    }
-    // Final add to mAppendEvents.
-    mAppendEvents.add(type);
-  }
-
-  protected void onCreate() {
-
-  }
-
-  public void bindHolder(IFComponentHolder holder) {
-    mHolder = holder;
-  }
-
-
-  public WXSDKInstance getInstance() {
-    return mInstance;
-  }
-
-  public Context getContext() {
-    return mContext;
-  }
-
-  /**
-   * Find component by component reference.
-   *
-   * @param ref
-   * @return
-   */
-  protected final WXComponent findComponent(String ref) {
-    if (mInstance != null && ref != null) {
-      return WXSDKManager.getInstance()
-              .getWXRenderManager()
-              .getWXComponent(mInstance.getInstanceId(), ref);
-    }
-    return null;
-  }
-
-  public String getAttrByKey(String key) {
-    return "default";
-  }
-
-  //Holding the animation bean when component is uninitialized
-  public void postAnimation(WXAnimationModule.AnimationHolder holder) {
-    this.mAnimationHolder = holder;
-  }
-
-  //This method will be removed once flatGUI is completed.
-  @RestrictTo(RestrictTo.Scope.LIBRARY)
-  public boolean isFlatUIEnabled() {
-    return mParent != null && mParent.isFlatUIEnabled();
-  }
-
-  private class OnClickListenerImp implements OnClickListener{
-    @Override
-    public void onHostViewClick() {
-      Map<String, Object> param = WXDataStructureUtil.newHashMapWithExpectedSize(1);
-      Map<String, Object> position = WXDataStructureUtil.newHashMapWithExpectedSize(4);
-      int[] location = new int[2];
-      mHost.getLocationOnScreen(location);
-      position.put("x", WXViewUtils.getWebPxByWidth(location[0], mInstance.getInstanceViewPortWidth()));
-      position.put("y", WXViewUtils.getWebPxByWidth(location[1], mInstance.getInstanceViewPortWidth()));
-      position.put("width", WXViewUtils.getWebPxByWidth(getLayoutWidth(), mInstance.getInstanceViewPortWidth()));
-      position.put("height", WXViewUtils.getWebPxByWidth(getLayoutHeight(), mInstance.getInstanceViewPortWidth()));
-      param.put(Constants.Name.POSITION, position);
-      fireEvent(Constants.Event.CLICK, param);
-    }
-  };
-  private OnClickListenerImp mClickEventListener;
-
-  public String getInstanceId() {
-    return mInstance.getInstanceId();
-  }
-
-  public Rect getComponentSize() {
-    Rect size = new Rect();
-    if (mHost != null) {
-      int[] location = new int[2];
-      int[] anchor = new int[2];
-      mHost.getLocationOnScreen(location);
-      mInstance.getContainerView().getLocationOnScreen(anchor);
-
-      int left = location[0] - anchor[0];
-      int top = (location[1] - mStickyOffset) - anchor[1];
-      int width = (int) getLayoutWidth();
-      int height = (int) getLayoutHeight();
-      size.set(left, top, left + width, top + height);
-    }
-    return size;
-  }
-
-  public final void invoke(String method, JSONArray args) {
-    final Invoker invoker = mHolder.getMethodInvoker(method);
-    if (invoker != null) {
-      try {
-        getInstance()
-                .getNativeInvokeHelper()
-                .invoke(this, invoker, args);
-
-      } catch (Exception e) {
-        WXLogUtils.e("[WXComponent] updateProperties :" + "class:" + getClass() + "method:" + invoker.toString() + " function " + WXLogUtils.getStackTrace(e));
-      }
-    } else {
-      onInvokeUnknownMethod(method, args);
-    }
-  }
-
-  /**
-   * Will be invoked when request method not found.
-   * Subclass should override this method, If you return hard-code method list in {@link IFComponentHolder#getMethods()}
-   *
-   * @param method
-   * @param args
-   */
-  protected void onInvokeUnknownMethod(String method, JSONArray args) {
-
-  }
-
-  public interface OnClickListener {
-    void onHostViewClick();
-  }
-
-  public interface OnFocusChangeListener{
-    void onFocusChange(boolean hasFocus);
-  }
-
-  public final void fireEvent(String type){
-    fireEvent(type,null);
-  }
-
-  public final void fireEvent(String type, Map<String, Object> params){
-    if(WXUtils.getBoolean(getAttrs().get("fireEventSyn"), false)){
-      fireEventWait(type, params);
-    }else{
-      fireEvent(type, params,null, null);
-    }
-  }
-
-  public final EventResult fireEventWait(String type, Map<String, Object> params){
-    final CountDownLatch waitLatch = new CountDownLatch(1);
-    EventResult callback = new EventResult(){
-      @Override
-      public void onCallback(Object result) {
-        super.onCallback(result);
-        waitLatch.countDown();
-      }
-    };
-    try{
-      fireEvent(type, params, null, callback);
-      waitLatch.await(50, TimeUnit.MILLISECONDS);
-      return  callback;
-    }catch (Exception e){
-      if(WXEnvironment.isApkDebugable()){
-        WXLogUtils.e("fireEventWait", e);
-      }
-      return  callback;
-    }
-  }
-
-  protected final void fireEvent(String type, Map<String, Object> params,Map<String, Object> domChanges){
-    fireEvent(type, params, domChanges, null);
-  }
-
-
-  private final void fireEvent(String type, Map<String, Object> params,Map<String, Object> domChanges, EventResult callback){
-    if(mInstance != null) {
-      List<Object> eventArgsValues = null;
-      if(getEvents() != null && getEvents().getEventBindingArgsValues() != null){
-        eventArgsValues = getEvents().getEventBindingArgsValues().get(type);
-      }
-      if(params != null){
-        String componentId = Statements.getComponentId(this);
-        if(componentId != null) {
-          params.put("componentId", componentId);
-        }
-      }
-      mInstance.fireEvent(getRef(), type, params,domChanges, eventArgsValues, callback);
-    }
-  }
-
-  /**
-   * find certain class type parent
-   * */
-  public  Object findTypeParent(WXComponent component, Class type){
-    if(component.getClass() == type){
-      return component;
-    }
-    if(component.getParent() != null) {
-      findTypeParent(component.getParent(), type);
-    }
-    return  null;
-  }
-
-  /**
-   * The view is created as needed
-   * @return true for lazy
-   */
-  public boolean isLazy() {
-    if(mLazy){
-      return true;
-    }
-    return mParent != null && mParent.isLazy();
-  }
-
-  protected final void addFocusChangeListener(OnFocusChangeListener l){
-    View view;
-    if(l != null && (view = getRealView()) != null) {
-      if( mFocusChangeListeners == null){
-        mFocusChangeListeners = new ArrayList<>();
-        view.setFocusable(true);
-        view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-          @Override
-          public void onFocusChange(View v, boolean hasFocus) {
-            for (OnFocusChangeListener listener : mFocusChangeListeners){
-              if(listener != null){
-                listener.onFocusChange(hasFocus);
-              }
-            }
-          }
-        });
-      }
-      mFocusChangeListeners.add(l);
-    }
-  }
-
-  protected final void addClickListener(OnClickListener l){
-    View view;
-    if(l != null && (view = getRealView()) != null) {
-      if(mHostClickListeners == null){
-        mHostClickListeners = new ArrayList<>();
-        view.setOnClickListener(new View.OnClickListener() {
-          @Override
-          public void onClick(View v) {
-            if(mGesture != null && mGesture.isTouchEventConsumedByAdvancedGesture()){
-              //event is already consumed by gesture
-              return;
-            }
-            for (OnClickListener listener : mHostClickListeners){
-              if(listener != null) {
-                listener.onHostViewClick();
-              }
-            }
-          }
-        });
-      }
-      mHostClickListeners.add(l);
-
-    }
-  }
-
-  protected final void removeClickListener(OnClickListener l) {
-    mHostClickListeners.remove(l);
-  }
-
-  public void bindData(WXComponent component) {
-    if (!isLazy()) {
-      if (component == null) {
-        component = this;
-      }
-      bindComponent(component);
-      updateStyles(component);
-      updateAttrs(component);
-      updateExtra(component.getExtra());
-    }
-  }
-
-  public void applyLayoutAndEvent(WXComponent component) {
-    if (!isLazy()) {
-      if (component == null) {
-        component = this;
-      }
-      bindComponent(component);
-      setSafeLayout(component);
-      setPadding(component.getPadding(), component.getBorder());
-      applyEvents();
-    }
-  }
-
-  public void setDemission(GraphicSize size, GraphicPosition position) {
-    setLayoutPosition(position);
-    setLayoutSize(size);
-  }
-
-  public void updateDemission(float top, float bottom, float left, float right, float height, float width) {
-    getLayoutPosition().update(top, bottom, left, right);
-    getLayoutSize().update(width, height);
-  }
-
-
-  public void applyLayoutOnly(){
-    if(!isLazy()) {
-      setSafeLayout(this);
-      setPadding(this.getPadding(), this.getBorder());
-    }
-  }
-
-
-  public void refreshData(WXComponent component) {
-
-  }
-
-  @Deprecated
-  public void updateProperties(Map<String, Object> props) {
-    if (props == null || (mHost == null && !isVirtualComponent())) {
-      return;
-    }
-
-    for (Map.Entry<String, Object> entry : props.entrySet()) {
-      Object key_obj = entry.getKey();
-      String key = WXUtils.getString(key_obj, null);
-      if ((key != null) && !(key_obj instanceof String)) {
-        Map<String, String> map = new HashMap<>();
-        map.put("componentType", getComponentType());
-        map.put("actual key", key == null ? "" : key);
-        WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
-            WXErrorCode.WX_RENDER_ERR_COMPONENT_ATTR_KEY,
-            "WXComponent.updateProperties",
-            WXErrorCode.WX_RENDER_ERR_COMPONENT_ATTR_KEY.getErrorMsg(),
-            map);
-      }
-
-      Object param = entry.getValue();
-      String value = WXUtils.getString(param, null);
-
-      if (key == null) {
-        WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
-                WXErrorCode.WX_RENDER_ERR_NULL_KEY, "updateProperties",
-                WXErrorCode.WX_RENDER_ERR_NULL_KEY.getErrorMsg(), null);
-      } else {
-        if (TextUtils.isEmpty(value)) {
-          param = convertEmptyProperty(key, value);
-        }
-        if (!setProperty(key, param)) {
-          if (mHolder == null) {
-            return;
-          }
-          Invoker invoker = mHolder.getPropertyInvoker(key);
-          if (invoker != null) {
-            try {
-              Type[] paramClazzs = invoker.getParameterTypes();
-              if (paramClazzs.length != 1) {
-                WXLogUtils.e("[WXComponent] setX method only one parameter:" + invoker);
-                return;
-              }
-              param = WXReflectionUtils.parseArgument(paramClazzs[0], param);
-              invoker.invoke(this, param);
-            } catch (Exception e) {
-              WXLogUtils.e("[WXComponent] updateProperties :" + "class:" + getClass() + "method:" + invoker.toString() + " function " + WXLogUtils.getStackTrace(e));
-            }
-          }
-        }
-      }
-    }
-    readyToRender();
-    if (this instanceof FlatComponent && mBackgroundDrawable != null) {
-      FlatComponent flatComponent = (FlatComponent) this;
-      if (!flatComponent.promoteToView(true) && !(flatComponent
-              .getOrCreateFlatWidget() instanceof AndroidViewWidget)) {
-        flatComponent.getOrCreateFlatWidget().setBackgroundAndBorder(mBackgroundDrawable);
-      }
-    }
-  }
-
-  /**
-   * Apply styles and attributes.
-   *
-   * @param key   name of argument
-   * @param param value of argument
-   * @return true means that the property is consumed
-   */
-  protected boolean setProperty(String key, Object param) {
-    if(key == null){
-      return true;
-    }
-    switch (key) {
-      case Constants.Name.PREVENT_MOVE_EVENT:
-        if (mGesture != null) {
-          mGesture.setPreventMoveEvent(WXUtils.getBoolean(param, false));
-        }
-        return true;
-      case Constants.Name.DISABLED:
-        Boolean disabled = WXUtils.getBoolean(param, null);
-        if (disabled != null) {
-          setDisabled(disabled);
-          setPseudoClassStatus(Constants.PSEUDO.DISABLED, disabled);
-        }
-        return true;
-      case Constants.Name.POSITION:
-        String position = WXUtils.getString(param, null);
-        if (position != null)
-          setSticky(position);
-        return true;
-      case Constants.Name.BACKGROUND_COLOR:
-        String bgColor = WXUtils.getString(param, null);
-        if (bgColor != null)
-          setBackgroundColor(bgColor);
-        return true;
-      case Constants.Name.BACKGROUND_IMAGE:
-        String bgImage = WXUtils.getString(param, null);
-        if (bgImage != null && mHost != null) {
-          setBackgroundImage(bgImage);
-        }
-        return true;
-      case Constants.Name.OPACITY:
-        Float opacity = WXUtils.getFloat(param, null);
-        if (opacity != null)
-          setOpacity(opacity);
-        return true;
-      case Constants.Name.BORDER_RADIUS:
-      case Constants.Name.BORDER_TOP_LEFT_RADIUS:
-      case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
-      case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
-      case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
-        Float radius = WXUtils.getFloat(param, null);
-        if (radius != null)
-          setBorderRadius(key, radius);
-        return true;
-      case Constants.Name.BORDER_STYLE:
-      case Constants.Name.BORDER_RIGHT_STYLE:
-      case Constants.Name.BORDER_BOTTOM_STYLE:
-      case Constants.Name.BORDER_LEFT_STYLE:
-      case Constants.Name.BORDER_TOP_STYLE:
-        String border_style = WXUtils.getString(param, null);
-        if (border_style != null)
-          setBorderStyle(key, border_style);
-        return true;
-      case Constants.Name.BORDER_COLOR:
-      case Constants.Name.BORDER_TOP_COLOR:
-      case Constants.Name.BORDER_RIGHT_COLOR:
-      case Constants.Name.BORDER_BOTTOM_COLOR:
-      case Constants.Name.BORDER_LEFT_COLOR:
-        String border_color = WXUtils.getString(param, null);
-        if (border_color != null)
-          setBorderColor(key, border_color);
-        return true;
-      case Constants.Name.VISIBILITY:
-        String visibility = WXUtils.getString(param, null);
-        if (visibility != null)
-          setVisibility(visibility);
-        return true;
-      case Constants.Name.ELEVATION:
-        if (param != null) {
-          updateElevation();
-        }
-        return true;
-      case PROP_FIXED_SIZE:
-        String fixedSize = WXUtils.getString(param, PROP_FS_MATCH_PARENT);
-        setFixedSize(fixedSize);
-        return true;
-      case Constants.Name.ARIA_LABEL:
-        String label = WXUtils.getString(param, "");
-        setAriaLabel(label);
-        return true;
-      case Constants.Name.ARIA_HIDDEN:
-        boolean isHidden = WXUtils.getBoolean(param, false);
-        setAriaHidden(isHidden);
-        return true;
-      case Constants.Name.WIDTH:
-      case Constants.Name.MIN_WIDTH:
-      case Constants.Name.MAX_WIDTH:
-      case Constants.Name.HEIGHT:
-      case Constants.Name.MIN_HEIGHT:
-      case Constants.Name.MAX_HEIGHT:
-      case Constants.Name.ALIGN_ITEMS:
-      case Constants.Name.ALIGN_SELF:
-      case Constants.Name.FLEX:
-      case Constants.Name.FLEX_DIRECTION:
-      case Constants.Name.JUSTIFY_CONTENT:
-      case Constants.Name.FLEX_WRAP:
-      case Constants.Name.MARGIN:
-      case Constants.Name.MARGIN_TOP:
-      case Constants.Name.MARGIN_LEFT:
-      case Constants.Name.MARGIN_RIGHT:
-      case Constants.Name.MARGIN_BOTTOM:
-      case Constants.Name.PADDING:
-      case Constants.Name.PADDING_TOP:
-      case Constants.Name.PADDING_LEFT:
-      case Constants.Name.PADDING_RIGHT:
-      case Constants.Name.PADDING_BOTTOM:
-      case Constants.Name.BORDER_WIDTH:
-      case Constants.Name.BORDER_TOP_WIDTH:
-      case Constants.Name.BORDER_RIGHT_WIDTH:
-      case Constants.Name.BORDER_BOTTOM_WIDTH:
-      case Constants.Name.BORDER_LEFT_WIDTH:
-      case Constants.Name.LEFT:
-      case Constants.Name.TOP:
-      case Constants.Name.RIGHT:
-      case Constants.Name.BOTTOM:
-        return true;
-      case Constants.Name.BOX_SHADOW:
-        try {
-          updateBoxShadow();
-        } catch (Throwable t) {
-          t.printStackTrace();
-        }
-        return true;
-      case Constants.Name.ROLE:
-        setRole(WXUtils.getString(param, ""));
-        return true;
-      default:
-        return false;
-    }
-  }
-
-  protected BorderDrawable getOrCreateBorder() {
-    if (mBackgroundDrawable == null) {
-      mBackgroundDrawable = new BorderDrawable();
-      if (mHost != null) {
-        WXViewUtils.setBackGround(mHost, null, this);
-        if (mRippleBackground == null) {
-          WXViewUtils.setBackGround(mHost, mBackgroundDrawable, this);
-        } else {
-          //TODO Not strictly clip according to background-clip:border-box
-          WXViewUtils.setBackGround(mHost, new LayerDrawable(new Drawable[]{
-                  mRippleBackground, mBackgroundDrawable}), this);
-        }
-      }
-    }
-    return mBackgroundDrawable;
-  }
-
-  /**
-   * layout view
-   */
-  public void setSafeLayout(WXComponent component) {
-    if (TextUtils.isEmpty(component.getComponentType())
-            || TextUtils.isEmpty(component.getRef()) || component.getLayoutPosition() == null
-            || component.getLayoutSize() == null) {
-      return;
-    }
-    setLayout(component);
-  }
-
-  /**
-   * layout view
-   */
-  public void setLayout(WXComponent component) {
-    setLayoutSize(component.getLayoutSize());
-    setLayoutPosition(component.getLayoutPosition());
-    setPaddings(component.getPadding());
-    setMargins(component.getMargin());
-    setBorders(component.getBorder());
-
-    boolean isRTL = component.isLayoutRTL();
-    setIsLayoutRTL(isRTL);
-    if (isRTL != component.isLastLayoutDirectionRTL) {
-      component.isLastLayoutDirectionRTL = isRTL;
-      layoutDirectionDidChanged(isRTL);
-    }
-
-    parseAnimation();
-
-    boolean nullParent = mParent == null;//parent is nullable
-
-    //offset by sibling
-    int siblingOffset = nullParent ? 0 : mParent.getChildrenLayoutTopOffset();
-
-    CSSShorthand parentPadding = (nullParent ? new CSSShorthand() : mParent.getPadding());
-    CSSShorthand parentBorder = (nullParent ? new CSSShorthand() : mParent.getBorder());
-
-    int realWidth = (int) getLayoutSize().getWidth();
-    int realHeight = (int) getLayoutSize().getHeight();
-
-    int realLeft = 0;
-    int realTop = 0;
-    int realRight = 0;
-
-    if (isFixed()) {
-      realLeft = (int) (getLayoutPosition().getLeft() - getInstance().getRenderContainerPaddingLeft());
-      realTop = (int) (getLayoutPosition().getTop() - getInstance().getRenderContainerPaddingTop()) + siblingOffset;
-    } else {
-      realLeft = (int) (getLayoutPosition().getLeft() -
-              parentPadding.get(CSSShorthand.EDGE.LEFT) - parentBorder.get(CSSShorthand.EDGE.LEFT));
-      realTop = (int) (getLayoutPosition().getTop() -
-              parentPadding.get(CSSShorthand.EDGE.TOP) - parentBorder.get(CSSShorthand.EDGE.TOP)) + siblingOffset;
-    }
-
-    realRight = (int) getMargin().get(CSSShorthand.EDGE.RIGHT);
-    int realBottom = (int) getMargin().get(CSSShorthand.EDGE.BOTTOM);
-
-    Point rawOffset = new Point(
-            (int) getLayoutPosition().getLeft(),
-            (int) getLayoutPosition().getTop());
-
-    if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft && mPreRealRight == realRight && mPreRealTop == realTop) {
-      return;
-    }
-
-    if (this instanceof WXCell && realHeight >= WXPerformance.VIEW_LIMIT_HEIGHT && realWidth>=WXPerformance.VIEW_LIMIT_WIDTH){
-      mInstance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_EXCEED_NUM,1);
-      mInstance.getWXPerformance().cellExceedNum++;
-      if (WXAnalyzerDataTransfer.isOpenPerformance){
-        WXAnalyzerDataTransfer.transferPerformance(getInstanceId(),"details",WXInstanceApm.KEY_PAGE_STATS_CELL_EXCEED_NUM,
-            String.format(Locale.ROOT, "cell:ref:%s,[w:%d,h:%d],attrs:%s,styles:%s",getRef(),realWidth,realHeight,getAttrs(),getStyles())
-        );
-      }
-
-    }
-
-    mAbsoluteY = (int) (nullParent ? 0 : mParent.getAbsoluteY() + getCSSLayoutTop());
-    mAbsoluteX = (int) (nullParent ? 0 : mParent.getAbsoluteX() + getCSSLayoutLeft());
-
-    if (mHost == null) {
-      return;
-    }
-
-    //calculate first screen time
-    if (!(mHost instanceof ViewGroup) && mAbsoluteY + realHeight > mInstance.getWeexHeight() + 1) {
-      if (!mInstance.mEnd){
-        mInstance.onOldFsRenderTimeLogic();
-      }
-      if (!mInstance.isNewFsEnd){
-        mInstance.isNewFsEnd = true;
-        mInstance.getApmForInstance().arriveNewFsRenderTime();
-      }
-    }
-
-    MeasureOutput measureOutput = measure(realWidth, realHeight);
-    realWidth = measureOutput.width;
-    realHeight = measureOutput.height;
-
-    setComponentLayoutParams(realWidth, realHeight, realLeft, realTop, realRight, realBottom, rawOffset);
-  }
-
-  private void setComponentLayoutParams(int realWidth, int realHeight, int realLeft, int realTop,
-                                        int realRight, int realBottom, Point rawOffset) {
-    if(getInstance() == null || getInstance().isDestroy()){
-      return;
-    }
-
-    FlatGUIContext UIImp = getInstance().getFlatUIContext();
-    WidgetContainer ancestor;
-    Widget widget;
-    if (UIImp != null && (ancestor = UIImp.getFlatComponentAncestor(this)) != null) {
-      if (this instanceof FlatComponent && !((FlatComponent) this).promoteToView(true)) {
-        widget = ((FlatComponent) this).getOrCreateFlatWidget();
-      } else {
-        widget = UIImp.getAndroidViewWidget(this);
-      }
-      setWidgetParams(widget, UIImp, rawOffset, realWidth, realHeight, realLeft, realRight, realTop,
-              realBottom);
-    } else if (mHost != null) {
-      // clear box shadow before host's size changed
-      clearBoxShadow();
-      if (isFixed()) {
-        setFixedHostLayoutParams(mHost, realWidth, realHeight, realLeft, realRight, realTop,
-                realBottom);
-      } else {
-        setHostLayoutParams(mHost, realWidth, realHeight, realLeft, realRight, realTop, realBottom);
-      }
-      recordInteraction(realWidth,realHeight);
-      mPreRealWidth = realWidth;
-      mPreRealHeight = realHeight;
-      mPreRealLeft = realLeft;
-      mPreRealRight = realRight;
-      mPreRealTop = realTop;
-      onFinishLayout();
-      // restore box shadow
-      updateBoxShadow();
-    }
-  }
-
-  /**
-   * layout direction is changed
-   * basic class is a empty implementation
-   * subclass can override this method do some RTL necessary things
-   * such as WXText
-   */
-  protected void layoutDirectionDidChanged(boolean isRTL) {
-
-  }
-
-  private void recordInteraction(int realWidth,int realHeight){
-    if (!mIsAddElementToTree){
-      return;
-    }
-    mIsAddElementToTree = false;
-    if (null == mParent){
-      interactionAbsoluteX = 0;
-      interactionAbsoluteY = 0;
-    }else {
-      float cssTop = getCSSLayoutTop();
-      float cssLeft = getCSSLayoutLeft();
-      interactionAbsoluteX = (int)(this.isFixed() ? cssLeft : mParent.interactionAbsoluteX + mParent.mChildrensWidth + cssLeft);
-      interactionAbsoluteY = (int)(this.isFixed() ? cssTop  : mParent.interactionAbsoluteY + cssTop);
-      //fix for slider impl ,and interactionTime calculate if component is out screen
-      if (WXBasicComponentType.SLIDER.equalsIgnoreCase(mParent.getComponentType()) || WXBasicComponentType.CYCLE_SLIDER.equalsIgnoreCase(mParent.getComponentType())){
-        if (!WXBasicComponentType.INDICATOR.equalsIgnoreCase(getComponentType())){
-          mParent.mChildrensWidth += (int)(realWidth + cssLeft);
-        }
-      }
-    }
-
-    if (null == getInstance().getApmForInstance().instanceRect){
-      getInstance().getApmForInstance().instanceRect = new Rect();
-    }
-    Rect instanceRect = getInstance().getApmForInstance().instanceRect;
-    instanceRect.set(0,0,mInstance.getWeexWidth(),mInstance.getWeexHeight());
-    boolean inScreen =
-          instanceRect.contains(interactionAbsoluteX,interactionAbsoluteY) //leftTop
-              || instanceRect.contains(interactionAbsoluteX+realWidth,interactionAbsoluteY)//rightTop
-              || instanceRect.contains(interactionAbsoluteX,interactionAbsoluteY+realHeight)//leftBottom
-              || instanceRect.contains(interactionAbsoluteX+realWidth,interactionAbsoluteY+realHeight);//rightBottom
-    mInstance.onChangeElement(this,!inScreen);
-  }
-
-  private void setWidgetParams(Widget widget, FlatGUIContext UIImp, Point rawoffset,
-                               int width, int height, int left, int right, int top, int bottom) {
-    Point childOffset = new Point();
-    if (mParent != null) {
-      if (mParent instanceof FlatComponent &&
-              UIImp.getFlatComponentAncestor(mParent) != null &&
-              UIImp.getAndroidViewWidget(mParent) == null) {
-        childOffset.set(rawoffset.x, rawoffset.y);
-      }
-      else{
-        childOffset.set(left, top);
-      }
-
-      if (mParent instanceof FlatComponent &&
-              UIImp.getFlatComponentAncestor(mParent) != null &&
-              UIImp.getAndroidViewWidget(mParent) == null) {
-        Point parentLayoutOffset = ((FlatComponent) mParent).getOrCreateFlatWidget().getLocInFlatContainer();
-        childOffset.offset(parentLayoutOffset.x, parentLayoutOffset.y);
-      }
-      ViewGroup.LayoutParams lp = mParent
-              .getChildLayoutParams(this, mHost, width, height, left, right, top, bottom);
-      if (lp instanceof ViewGroup.MarginLayoutParams) {
-        width = lp.width;
-        height = lp.height;
-        left = ((ViewGroup.MarginLayoutParams) lp).leftMargin;
-        right = ((ViewGroup.MarginLayoutParams) lp).rightMargin;
-        top = ((ViewGroup.MarginLayoutParams) lp).topMargin;
-        bottom = ((ViewGroup.MarginLayoutParams) lp).bottomMargin;
-      }
-    }
-    widget.setLayout(width, height, left, right, top, bottom, childOffset);
-
-    if (widget instanceof AndroidViewWidget && ((AndroidViewWidget) widget).getView()!=null) {
-      //TODO generic method if ever possible
-      setHostLayoutParams((T) ((AndroidViewWidget) widget).getView(),
-              width, height, childOffset.x, right, childOffset.y, bottom);
-    }
-  }
-
-  public int getLayoutTopOffsetForSibling() {
-    return 0;
-  }
-
-  protected void setHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom) {
-    ViewGroup.LayoutParams lp;
-    if (mParent == null) {
-        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
-        this.setMarginsSupportRTL(params, left, top, right, bottom);
-        lp = params;
-    } else {
-        lp = mParent.getChildLayoutParams(this, host, width, height, left, right, top, bottom);
-    }
-    if (lp != null) {
-        host.setLayoutParams(lp);
-    }
-  }
-
-  private void setFixedHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom){
-    FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
-    params.width = width;
-    params.height = height;
-
-    this.setMarginsSupportRTL(params, left, top, right, bottom);
-
-    host.setLayoutParams(params);
-    mInstance.moveFixedView(host);
-
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout :" + left + " " + top + " " + width + " " + height);
-      WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout Left:" + getStyles().getLeft() + " " + (int) getStyles().getTop());
-    }
-  }
-
-  protected void updateBoxShadow() {
-    if (!BoxShadowUtil.isBoxShadowEnabled()) {
-//      WXLogUtils.w("BoxShadow", "box-shadow disabled");
-      return;
-    }
-
-    if (getStyles() != null) {
-      Object boxShadow = getStyles().get(Constants.Name.BOX_SHADOW);
-      Object shadowQuality = getAttrs().get(Constants.Name.SHADOW_QUALITY);
-      if (boxShadow == null) {
-        return;
-      }
-
-      View target = mHost;
-      if (this instanceof WXVContainer) {
-        target = ((WXVContainer) this).getBoxShadowHost(false);
-      }
-
-      if (target == null) {
-        return;
-      }
-
-      float quality = WXUtils.getFloat(shadowQuality, 0.5f);
-      int viewPort = getInstance().getInstanceViewPortWidth();
-      String token = new StringBuilder(boxShadow.toString()).append(" / [")
-              .append(target.getMeasuredWidth()).append(",")
-              .append(target.getMeasuredHeight()).append("] / ")
-              .append(quality).toString();
-
-      if (mLastBoxShadowId != null && mLastBoxShadowId.equals(token)) {
-        WXLogUtils.d("BoxShadow", "box-shadow style was not modified. " + token);
-        return;
-      }
-
-      float[] radii = new float[]{0, 0, 0, 0, 0, 0, 0, 0};
-      WXStyle style = getStyles();
-      if (style != null) {
-        float tl = WXUtils.getFloat(style.get(Constants.Name.BORDER_TOP_LEFT_RADIUS), 0f);
-        radii[0] = tl;
-        radii[1] = tl;
-
-        float tr = WXUtils.getFloat(style.get(Constants.Name.BORDER_TOP_RIGHT_RADIUS), 0f);
-        radii[2] = tr;
-        radii[3] = tr;
-
-        float br = WXUtils.getFloat(style.get(Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS), 0f);
-        radii[4] = br;
-        radii[5] = br;
-
-        float bl = WXUtils.getFloat(style.get(Constants.Name.BORDER_BOTTOM_LEFT_RADIUS), 0f);
-        radii[6] = bl;
-        radii[7] = bl;
-
-        if (style.containsKey(Constants.Name.BORDER_RADIUS)) {
-          float radius = WXUtils.getFloat(style.get(Constants.Name.BORDER_RADIUS), 0f);
-          for (int i = 0; i < radii.length; i++) {
-            radii[i] = radius;
-          }
-        }
-      }
-
-      BoxShadowUtil.setBoxShadow(target, boxShadow.toString(), radii, viewPort, quality);
-      mLastBoxShadowId = token;
-    } else {
-      WXLogUtils.w("Can not resolve styles");
-    }
-  }
-
-  protected void clearBoxShadow() {
-    if (!BoxShadowUtil.isBoxShadowEnabled()) {
-//      WXLogUtils.w("BoxShadow", "box-shadow disabled");
-      return;
-    }
-
-    if (getStyles() != null) {
-      Object obj = getStyles().get(Constants.Name.BOX_SHADOW);
-      if (obj == null) {
-        return;
-      }
-    }
-
-    View target = mHost;
-    if (this instanceof WXVContainer) {
-      target = ((WXVContainer) this).getBoxShadowHost(true);
-    }
-
-    if (target != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-      ViewOverlay overlay = target.getOverlay();
-      if (overlay != null) {
-        overlay.clear();
-      }
-    }
-    mLastBoxShadowId = null;
-  }
-
-  /**
-   * After component's layout result is apply to view. May be invoke multiple times since
-   * DOM can be changed in js runtime.
-   */
-  protected void onFinishLayout() {
-    Object param = getStyles() != null ? getStyles().get(Constants.Name.BACKGROUND_IMAGE) : null;
-    if (param != null) {
-      setBackgroundImage(param.toString());
-    }
-  }
-
-  /**
-   * measure
-   */
-  protected MeasureOutput measure(int width, int height) {
-    MeasureOutput measureOutput = new MeasureOutput();
-
-    if (mFixedProp != 0) {
-      measureOutput.width = mFixedProp;
-      measureOutput.height = mFixedProp;
-    } else {
-      measureOutput.width = width;
-      measureOutput.height = height;
-    }
-    return measureOutput;
-  }
-
-  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-  protected void setAriaHidden(boolean isHidden) {
-    View host = getHostView();
-    if (host != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-      host.setImportantForAccessibility(isHidden ? View.IMPORTANT_FOR_ACCESSIBILITY_NO : View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-    }
-  }
-
-  protected void setAriaLabel(String label) {
-    View host = getHostView();
-    if (host != null) {
-      host.setContentDescription(label);
-    }
-  }
-
-  protected void setRole(String roleKey) {
-    View host = getHostView();
-    String role = roleKey;
-    if (host != null && !TextUtils.isEmpty(roleKey)) {
-      IWXAccessibilityRoleAdapter roleAdapter = WXSDKManager.getInstance().getAccessibilityRoleAdapter();
-      if (roleAdapter != null) {
-        role = roleAdapter.getRole(roleKey);
-      }
-      final String finalRole = role;
-      AccessibilityDelegateCompat delegate = new AccessibilityDelegateCompat() {
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-          try {
-            super.onInitializeAccessibilityNodeInfo(host, info);
-            info.setRoleDescription(finalRole);
-          } catch (Throwable e) {
-            WXLogUtils.e("SetRole failed!");
-          }
-        }
-      };
-      ViewCompat.setAccessibilityDelegate(host, delegate);
-    }
-  }
-
-  /**
-   * Avoid large size view fail in GPU-Animation.
-   *
-   * @param fixedSize
-   */
-  private void setFixedSize(String fixedSize) {
-    if (PROP_FS_MATCH_PARENT.equals(fixedSize)) {
-      mFixedProp = ViewGroup.LayoutParams.MATCH_PARENT;
-    } else if (PROP_FS_WRAP_CONTENT.equals(fixedSize)) {
-      mFixedProp = ViewGroup.LayoutParams.WRAP_CONTENT;
-    } else {
-      mFixedProp = 0;
-      return;
-    }
-    if (mHost != null) {
-      ViewGroup.LayoutParams layoutParams = mHost.getLayoutParams();
-      if (layoutParams != null) {
-        layoutParams.height = mFixedProp;
-        layoutParams.width = mFixedProp;
-        mHost.setLayoutParams(layoutParams);
-      }
-    }
-  }
-
-  /**
-   * Add new event to component,this will post a task to DOM thread to add event.
-   *
-   * @param type
-   */
-  protected void appendEventToDOM(String type) {
-//    WXSDKManager.getInstance().getWXDomManager().postAction(getInstanceId(), Actions.getAddEvent(getRef(), type), false);
-  }
-
-  public View getRealView() {
-    return mHost;
-  }
-
-  /**
-   * Judge whether need to set an onTouchListener.<br>
-   * As there is only one onTouchListener in each view, so all the gesture that use onTouchListener should put there.
-   *
-   * @param type eventType {@link com.taobao.weex.common.Constants.Event}
-   * @return true for set an onTouchListener, otherwise false
-   */
-  private boolean needGestureDetector(String type) {
-    if (mHost != null) {
-      for (WXGestureType gesture : WXGestureType.LowLevelGesture.values()) {
-        if (type.equals(gesture.toString())) {
-          return true;
-        }
-      }
-      for (WXGestureType gesture : WXGestureType.HighLevelGesture.values()) {
-        if (type.equals(gesture.toString())) {
-          return true;
-        }
-      }
-    }
-    if(WXGesture.isStopPropagation(type)){
-      return  true;
-    }
-    return false;
-  }
-
-  /**
-   * get Scroller components
-   */
-  public Scrollable getParentScroller() {
-    WXComponent component = this;
-    WXVContainer container;
-    Scrollable scroller;
-    for (; ; ) {
-      container = component.getParent();
-      if (container == null) {
-        return null;
-      }
-      if (container instanceof Scrollable) {
-        scroller = (Scrollable) container;
-        return scroller;
-      }
-      if (container.getRef().equals(ROOT)) {
-        return null;
-      }
-      component = container;
-    }
-  }
-
-  /**
-   * get Scroller components
-   */
-  @Nullable
-  public Scrollable getFirstScroller() {
-    if (this instanceof Scrollable) {
-      return (Scrollable) this;
-    }
-    return null;
-  }
-
-  public WXVContainer getParent() {
-    return mParent;
-  }
-
-  /**
-   * create view
-   */
-  public final void createView() {
-    if (!isLazy()) {
-      createViewImpl();
-    }
-  }
-
-  protected void createViewImpl() {
-    if (mContext != null) {
-      mHost = initComponentHostView(mContext);
-      if (mHost == null && !isVirtualComponent()) {
-        //compatible
-        initView();
-      }
-      if (mHost != null) {
-        if(mHost.getId() == View.NO_ID)
-          mHost.setId(WXViewUtils.generateViewId());
-        if(TextUtils.isEmpty(mHost.getContentDescription()) && WXEnvironment.isApkDebugable()){
-          mHost.setContentDescription(getRef());
-        }
-        ComponentObserver observer;
-        if ((observer = getInstance().getComponentObserver()) != null) {
-          observer.onViewCreated(this, mHost);
-        }
-      }
-      onHostViewInitialized(mHost);
-    } else {
-      WXLogUtils.e("createViewImpl", "Context is null");
-    }
-  }
-
-  /**
-   * Use {@link #initComponentHostView(Context context)} instead.
-   */
-  @Deprecated
-  protected void initView() {
-    if (mContext != null)
-      mHost = initComponentHostView(mContext);
-  }
-
-
-  /**
-   * Create corresponding view for this component.
-   *
-   * @param context
-   * @return
-   */
-  protected T initComponentHostView(@NonNull Context context) {
-    /**
-     * compatible old initView
-     */
-    return null;
-  }
-
-  /**
-   * Called after host view init. <br>
-   * Any overriding methods should invoke this method at the right time, to ensure the cached animation can be triggered correctly.
-   * (the animation will be cached when {@link #isLazy()} is true)
-   *
-   * @param host the host view
-   */
-  @CallSuper
-  protected void onHostViewInitialized(T host) {
-    if (mAnimationHolder != null) {
-//      Performs cached animation
-      mAnimationHolder.execute(mInstance, this);
-    }
-    setActiveTouchListener();
-  }
-
-  public T getHostView() {
-    return mHost;
-  }
-
-  /**
-   * use {@link #getHostView()} instead
-   *
-   * @return
-   */
-  @Deprecated
-  public View getView() {
-    return mHost;
-  }
-
-  public int getAbsoluteY() {
-    return mAbsoluteY;
-  }
-
-  public int getAbsoluteX() {
-    return mAbsoluteX;
-  }
-
-  public void removeEvent(String type) {
-    if (TextUtils.isEmpty(type)) {
-      return;
-    }
-
-    if (type.equals(Constants.Event.LAYEROVERFLOW))
-      removeLayerOverFlowListener(getRef());
-
-    if(getEvents() != null){
-      getEvents().remove(type);
-    }
-    if(mAppendEvents != null) {
-      mAppendEvents.remove(type);//only clean append events, not dom's events.
-    }
-    if(mGestureType != null){
-      mGestureType.remove(type);
-    }
-    removeEventFromView(type);
-  }
-
-  protected void removeEventFromView(String type) {
-    if (type.equals(Constants.Event.CLICK) && getRealView() != null && mHostClickListeners != null) {
-      if(mClickEventListener == null){
-        mClickEventListener = new OnClickListenerImp();
-      }
-      mHostClickListeners.remove(mClickEventListener);
-      //click event only remove from listener array
-    }
-    Scrollable scroller = getParentScroller();
-    if (type.equals(Constants.Event.APPEAR) && scroller != null) {
-      scroller.unbindAppearEvent(this);
-    }
-    if (type.equals(Constants.Event.DISAPPEAR) && scroller != null) {
-      scroller.unbindDisappearEvent(this);
-    }
-  }
-
-  public void removeAllEvent() {
-    if (getEvents().size() < 1) {
-      return;
-    }
-    WXEvent events = getEvents();
-    int size = events.size();
-    for (int i=0; i<size; i++) {
-      if(i >= events.size()){
-        break;
-      }
-      String event = events.get(i);
-      if (event == null) {
-        continue;
-      }
-      removeEventFromView(event);
-    }
-    if(mAppendEvents!=null) {
-      mAppendEvents.clear();//only clean append events, not dom's events.
-    }
-    if(mGestureType != null){
-      mGestureType.clear();
-    }
-    mGesture = null;
-    if (getRealView() != null &&
-            getRealView() instanceof WXGestureObservable) {
-      ((WXGestureObservable) getRealView()).registerGestureListener(null);
-    }
-    if (mHost != null) {
-      mHost.setOnFocusChangeListener(null);
-      if (mHostClickListeners != null && mHostClickListeners.size() > 0) {
-        mHostClickListeners.clear();
-        mHost.setOnClickListener(null);
-      }
-    }
-  }
-
-  public final void removeStickyStyle() {
-    if (isSticky()) {
-      Scrollable scroller = getParentScroller();
-      if (scroller != null) {
-        scroller.unbindStickStyle(this);
-      }
-    }
-  }
-
-  public boolean isSticky() {
-    return getStyles().isSticky();
-  }
-
-  public boolean isFixed() {
-    return getStyles().isFixed();
-  }
-
-  public void setDisabled(boolean disabled) {
-    mIsDisabled = disabled;
-    if (mHost == null) {
-      return;
-    }
-    mHost.setEnabled(!disabled);
-  }
-
-  public boolean isDisabled() {
-    return mIsDisabled;
-  }
-
-  public void setSticky(String sticky) {
-    if (!TextUtils.isEmpty(sticky) && sticky.equals(Constants.Value.STICKY)) {
-      Scrollable waScroller = getParentScroller();
-      if (waScroller != null) {
-        waScroller.bindStickStyle(this);
-      }
-    }
-  }
-
-  public void setBackgroundColor(String color) {
-    if (!TextUtils.isEmpty(color)) {
-      int colorInt = WXResourceUtils.getColor(color);
-      if (isRippleEnabled() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-        mRippleBackground = prepareBackgroundRipple();
-        if (mRippleBackground != null) {
-          if (mBackgroundDrawable == null) {
-            WXViewUtils.setBackGround(mHost, mRippleBackground, this);
-          } else {
-            LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{mRippleBackground, mBackgroundDrawable});
-            WXViewUtils.setBackGround(mHost, layerDrawable, this);
-          }
-          return;
-        }
-      }
-      if (!(colorInt == Color.TRANSPARENT && mBackgroundDrawable == null)) {
-        getOrCreateBorder().setColor(colorInt);
-      }
-    }
-  }
-
-  private Drawable prepareBackgroundRipple() {
-    try {
-      if (getStyles() != null && getStyles().getPesudoResetStyles() != null) {
-        Map<String, Object> resetStyles = getStyles().getPesudoResetStyles();
-
-        Object bgColor = resetStyles.get(Constants.Name.BACKGROUND_COLOR);
-        int colorInt = Color.TRANSPARENT;
-        if (bgColor != null) {
-          colorInt = WXResourceUtils.getColor(bgColor.toString(), Color.TRANSPARENT);
-          if (colorInt == Color.TRANSPARENT) {
-            return null;
-          }
-        }
-
-        Object bg = resetStyles.get(Constants.Name.BACKGROUND_COLOR + Constants.PSEUDO.ACTIVE);
-        if (bg == null) {
-          return null;
-        }
-        int rippleColor = WXResourceUtils.getColor(bg.toString(), colorInt);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-          ColorStateList colorStateList = new ColorStateList(
-                  new int[][]{new int[]{}},
-                  new int[]{rippleColor});
-          return new RippleDrawable(colorStateList, new ColorDrawable(colorInt), null) {
-            @Override
-            @SuppressLint("CanvasSize")
-            public void draw(@NonNull Canvas canvas) {
-              if (mBackgroundDrawable != null) {
-                Path border = mBackgroundDrawable.getContentPath(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()));
-                canvas.clipPath(border);
-              }
-              super.draw(canvas);
-            }
-          };
-        }
-      }
-    } catch (Throwable t) {
-      WXLogUtils.w("Exception on create ripple: ", t);
-    }
-    return null;
-  }
-
-  public void setBackgroundImage(@NonNull String bgImage) {
-    if ("".equals(bgImage.trim())) {
-      getOrCreateBorder().setImage(null);
-    } else {
-      Shader shader = WXResourceUtils.getShader(bgImage, getLayoutSize().getWidth(), getLayoutSize().getHeight());
-      getOrCreateBorder().setImage(shader);
-    }
-  }
-  private boolean shouldCancelHardwareAccelerate() {
-    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
-    boolean cancel_hardware_accelerate = true;
-    if (adapter != null) {
-      try {
-        cancel_hardware_accelerate = Boolean.parseBoolean(adapter
-                .getConfig("android_weex_test_gpu",
-                        "cancel_hardware_accelerate",
-                        "true"));
-      }catch (Exception e){
-        WXLogUtils.e(WXLogUtils.getStackTrace(e));
-      }
-      WXLogUtils.i("cancel_hardware_accelerate : " + cancel_hardware_accelerate);
-    }
-    return cancel_hardware_accelerate;
-  }
-
-  public void setOpacity(float opacity) {
-    if (opacity >= 0 && opacity <= 1 && mHost.getAlpha() != opacity) {
-      int limit = WXRenderManager.getOpenGLRenderLimitValue();
-      if (isLayerTypeEnabled()) {
-        mHost.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-      }
-      if(isLayerTypeEnabled() && shouldCancelHardwareAccelerate() && limit > 0 && (getLayoutHeight() > limit ||
-              getLayoutWidth() > limit)){
-        mHost.setLayerType(View.LAYER_TYPE_NONE,null);
-      }
-      mHost.setAlpha(opacity);
-    }
-  }
-
-  public void setBorderRadius(String key, float borderRadius) {
-    if (borderRadius >= 0) {
-      switch (key) {
-        case Constants.Name.BORDER_RADIUS:
-          getOrCreateBorder().setBorderRadius(
-              CORNER.ALL, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
-          break;
-        case Constants.Name.BORDER_TOP_LEFT_RADIUS:
-          getOrCreateBorder().setBorderRadius(CORNER.BORDER_TOP_LEFT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
-          break;
-        case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
-          getOrCreateBorder().setBorderRadius(CORNER.BORDER_TOP_RIGHT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
-          break;
-        case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
-          getOrCreateBorder().setBorderRadius(CORNER.BORDER_BOTTOM_RIGHT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
-          break;
-        case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
-          getOrCreateBorder().setBorderRadius(CORNER.BORDER_BOTTOM_LEFT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
-          break;
-      }
-    }
-  }
-
-  public void setBorderWidth(String key, float borderWidth) {
-    if (borderWidth >= 0) {
-      switch (key) {
-        case Constants.Name.BORDER_WIDTH:
-          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.ALL, borderWidth);
-          break;
-        case Constants.Name.BORDER_TOP_WIDTH:
-          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.TOP, borderWidth);
-          break;
-        case Constants.Name.BORDER_RIGHT_WIDTH:
-          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.RIGHT, borderWidth);
-          break;
-        case Constants.Name.BORDER_BOTTOM_WIDTH:
-          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.BOTTOM, borderWidth);
-          break;
-        case Constants.Name.BORDER_LEFT_WIDTH:
-          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.LEFT, borderWidth);
-          break;
-        default:
-          break;
-      }
-    }
-  }
-
-  public void setBorderStyle(String key, String borderStyle) {
-    if (!TextUtils.isEmpty(borderStyle)) {
-      switch (key) {
-        case Constants.Name.BORDER_STYLE:
-          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.ALL, borderStyle);
-          break;
-        case Constants.Name.BORDER_RIGHT_STYLE:
-          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.RIGHT, borderStyle);
-          break;
-        case Constants.Name.BORDER_BOTTOM_STYLE:
-          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.BOTTOM, borderStyle);
-          break;
-        case Constants.Name.BORDER_LEFT_STYLE:
-          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.LEFT, borderStyle);
-          break;
-        case Constants.Name.BORDER_TOP_STYLE:
-          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.TOP, borderStyle);
-          break;
-      }
-    }
-  }
-
-  public void setBorderColor(String key, String borderColor) {
-    if (!TextUtils.isEmpty(borderColor)) {
-      int colorInt = WXResourceUtils.getColor(borderColor);
-      if (colorInt != Integer.MIN_VALUE) {
-        switch (key) {
-          case Constants.Name.BORDER_COLOR:
-            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.ALL, colorInt);
-            break;
-          case Constants.Name.BORDER_TOP_COLOR:
-            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.TOP, colorInt);
-            break;
-          case Constants.Name.BORDER_RIGHT_COLOR:
-            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.RIGHT, colorInt);
-            break;
-          case Constants.Name.BORDER_BOTTOM_COLOR:
-            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.BOTTOM, colorInt);
-            break;
-          case Constants.Name.BORDER_LEFT_COLOR:
-            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.LEFT, colorInt);
-            break;
-        }
-      }
-    }
-  }
-
-  public
-  @Nullable
-  String getVisibility() {
-    try {
-      return (String) getStyles().get(Constants.Name.VISIBILITY);
-    } catch (Exception e) {
-      return Constants.Value.VISIBLE;
-    }
-  }
-
-  public void setVisibility(String visibility) {
-    View view;
-    if ((view = getRealView()) != null) {
-      if (TextUtils.equals(visibility, Constants.Value.VISIBLE)) {
-        view.setVisibility(View.VISIBLE);
-      } else if (TextUtils.equals(visibility, Constants.Value.HIDDEN)) {
-        view.setVisibility(View.GONE);
-      }
-    }
-  }
-
-  /**
-   * This is an experimental feature for elevation of material design.
-   */
-  private void updateElevation() {
-    float elevation = getAttrs().getElevation(getInstance().getInstanceViewPortWidth());
-    if (!Float.isNaN(elevation)) {
-      ViewCompat.setElevation(getHostView(), elevation);
-    }
-  }
-
-  @Deprecated
-  public void registerActivityStateListener() {
-
-  }
-
-
-  /********************************
-   *  begin hook Activity life cycle callback
-   ********************************************************/
-  public void onActivityCreate() {
-
-  }
-
-  public void onActivityStart() {
-
-  }
-
-  public void onActivityPause() {
-
-  }
-
-  public void onActivityResume() {
-
-  }
-
-  public void onActivityStop() {
-
-  }
-
-  public void onActivityDestroy() {
-
-  }
-
-  public boolean onActivityBack() {
-    return false;
-  }
-
-  public void onActivityResult(int requestCode, int resultCode, Intent data) {
-
-  }
-
-  public boolean onCreateOptionsMenu(Menu menu) {
-    return false;
-  }
-
-  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
-
-  }
-
-  /********************************
-   *  end hook Activity life cycle callback
-   ********************************************************/
-  public void recycled() {
-    if (isFixed())
-      return;
-    clearBoxShadow();
-  }
-
-  public void destroy() {
-    ComponentObserver observer;
-    if ((observer = getInstance().getComponentObserver()) != null) {
-      observer.onPreDestory(this);
-    }
-
-    if (WXEnvironment.isApkDebugable() && !WXUtils.isUiThread()) {
-      throw new WXRuntimeException("[WXComponent] destroy can only be called in main thread");
-    }
-    if (mHost != null && mHost.getLayerType() == View.LAYER_TYPE_HARDWARE && isLayerTypeEnabled()) {
-      mHost.setLayerType(View.LAYER_TYPE_NONE, null);
-    }
-    removeAllEvent();
-    removeStickyStyle();
-
-    View view;
-    if (isFixed() && (view = getHostView()) != null) {
-      getInstance().removeFixedView(view);
-    }
-
-    if(contentBoxMeasurement!=null){
-      contentBoxMeasurement.destroy();
-      contentBoxMeasurement = null;
-    }
-    mIsDestroyed = true;
-    if(animations!=null) {
-      animations.clear();
-    }
-  }
-
-  public boolean isDestoryed() {
-    return mIsDestroyed;
-  }
-
-  /**
-   * Detach view from its component. Components,
-   * which have difference between getHostView and getRealView or have temp calculation results,
-   * must<strong> override</strong>  this method with their own implementation.
-   *
-   * @return the original View
-   */
-  public View detachViewAndClearPreInfo() {
-    View original = mHost;
-    mPreRealLeft = 0;
-    mPreRealRight = 0;
-    mPreRealWidth = 0;
-    mPreRealHeight = 0;
-    mPreRealTop = 0;
-//    mHost = null;
-    return original;
-  }
-
-  public void clearPreLayout() {
-    mPreRealLeft = 0;
-    mPreRealRight = 0;
-    mPreRealWidth = 0;
-    mPreRealHeight = 0;
-    mPreRealTop = 0;
-  }
-
-  /**
-   * This method computes user visible left-top point in view's coordinate.
-   * The default implementation uses the scrollX and scrollY of the view as the result,
-   * and put the value in the parameter pointer.
-   * Components with different computation algorithm
-   * <strong> should override </strong> this method.
-   *
-   * @param pointF the user visible left-top point in view's coordinate.
-   */
-  public void computeVisiblePointInViewCoordinate(PointF pointF) {
-    View view = getRealView();
-    pointF.set(view.getScrollX(), view.getScrollY());
-  }
-
-  public boolean containsGesture(WXGestureType WXGestureType) {
-    return mGestureType != null && mGestureType.contains(WXGestureType.toString());
-  }
-
-  public boolean containsEvent(String event) {
-    return getEvents().contains(event) || (mAppendEvents!=null && mAppendEvents.contains(event));
-  }
-
-  public void notifyAppearStateChange(String wxEventType, String direction) {
-    if (containsEvent(Constants.Event.APPEAR) || containsEvent(Constants.Event.DISAPPEAR)) {
-      Map<String, Object> params = new HashMap<>();
-      params.put("direction", direction);
-      fireEvent(wxEventType, params);
-    }
-  }
-
-  public boolean isUsing() {
-    return isUsing;
-  }
-
-  public void setUsing(boolean using) {
-    isUsing = using;
-  }
-
-  public void readyToRender() {
-    if (mParent != null && getInstance().isTrackComponent()) {
-      mParent.readyToRender();
-    }
-  }
-
-  public static class MeasureOutput {
-    public int width;
-    public int height;
-  }
-
-  /**
-   * Determine whether the current component needs to be placed in the real View tree
-   *
-   * @return false component add subview
-   */
-  public boolean isVirtualComponent() {
-    return mType == TYPE_VIRTUAL;
-  }
-
-  public void removeVirtualComponent() {
-  }
-
-  public int getType() {
-    return mType;
-  }
-
-  public boolean hasScrollParent(WXComponent component) {
-    if (component.getParent() == null) {
-      return true;
-    } else if (component.getParent() instanceof WXScroller) {
-      return false;
-    } else {
-      return hasScrollParent(component.getParent());
-    }
-  }
-
-  /**
-   * Called when property has empty value
-   *
-   * @param propName
-   */
-  @CheckResult
-  protected Object convertEmptyProperty(String propName, Object originalValue) {
-    switch (propName) {
-      case Constants.Name.BACKGROUND_COLOR:
-        return "transparent";
-      case Constants.Name.BORDER_RADIUS:
-      case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
-      case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
-      case Constants.Name.BORDER_TOP_LEFT_RADIUS:
-      case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
-        return 0;
-      case Constants.Name.BORDER_WIDTH:
-      case Constants.Name.BORDER_TOP_WIDTH:
-      case Constants.Name.BORDER_LEFT_WIDTH:
-      case Constants.Name.BORDER_RIGHT_WIDTH:
-      case Constants.Name.BORDER_BOTTOM_WIDTH:
-        return 0;
-      case Constants.Name.BORDER_COLOR:
-      case Constants.Name.BORDER_TOP_COLOR:
-      case Constants.Name.BORDER_LEFT_COLOR:
-      case Constants.Name.BORDER_RIGHT_COLOR:
-      case Constants.Name.BORDER_BOTTOM_COLOR:
-        return "black";
-    }
-    return originalValue;
-  }
-
-  private void setActiveTouchListener() {
-    boolean hasActivePesudo = getStyles().getPesudoStyles().containsKey(Constants.PSEUDO.ACTIVE);
-    View view;
-    if (hasActivePesudo && (view = getRealView()) != null) {
-      boolean hasTouchConsumer = isConsumeTouch();
-      view.setOnTouchListener(new TouchActivePseudoListener(this, !hasTouchConsumer));
-    }
-  }
-
-  protected boolean isConsumeTouch() {
-    return (mHostClickListeners != null && mHostClickListeners.size() > 0) || mGesture != null;
-  }
-
-  @Override
-  public void updateActivePseudo(boolean isSet) {
-    setPseudoClassStatus(Constants.PSEUDO.ACTIVE, isSet);
-  }
-
-  /**
-   * @param clzName like ':active' or ':active:enabled'
-   * @param status
-   */
-  protected void setPseudoClassStatus(String clzName, boolean status) {
-    WXStyle styles = getStyles();
-    Map<String, Map<String, Object>> pesudoStyles = styles.getPesudoStyles();
-
-    if (pesudoStyles == null || pesudoStyles.size() == 0) {
-      return;
-    }
-    if(mPesudoStatus == null){
-      mPesudoStatus = new PesudoStatus();
-    }
-    Map<String, Object> resultStyles = mPesudoStatus.updateStatusAndGetUpdateStyles(
-            clzName,
-            status,
-            pesudoStyles,
-            styles.getPesudoResetStyles());
-
-    if (null != resultStyles) {
-      if (status) {
-        mPseudoResetGraphicSize = new GraphicSize(getLayoutSize().getWidth(), getLayoutSize().getHeight());
-        if (resultStyles.keySet().contains(Constants.Name.WIDTH)) {
-          getLayoutSize().setWidth(WXViewUtils.getRealPxByWidth(WXUtils.parseFloat(styles.getPesudoResetStyles().get(Constants.Name.WIDTH + Constants.PSEUDO.ACTIVE)), getViewPortWidth()));
-        } else if (resultStyles.keySet().contains(Constants.Name.HEIGHT)){
-          getLayoutSize().setHeight(WXViewUtils.getRealPxByWidth(WXUtils.parseFloat(styles.getPesudoResetStyles().get(Constants.Name.HEIGHT + Constants.PSEUDO.ACTIVE)), getViewPortWidth()));
-        }
-      } else {
-        if (null != mPseudoResetGraphicSize) {
-          setLayoutSize(mPseudoResetGraphicSize);
-        }
-      }
-    }
-
-    updateStyleByPesudo(resultStyles);
-  }
-
-  private void updateStyleByPesudo(Map<String, Object> styles) {
-    new GraphicActionUpdateStyle(getInstance(), getRef(), styles, getPadding(), getMargin(), getBorder(), true)
-            .executeActionOnRender();
-    if (getLayoutWidth() == 0 && getLayoutWidth() == 0) {
-    } else {
-      WXBridgeManager.getInstance().setStyleWidth(getInstanceId(), getRef(), getLayoutWidth());
-      WXBridgeManager.getInstance().setStyleHeight(getInstanceId(), getRef(), getLayoutHeight());
-//      WXBridgeManager.getInstance().calculateLayout(getInstanceId(), getRef(), false);
-    }
-  }
-
-  public int getStickyOffset() {
-    return mStickyOffset;
-  }
-
-  public boolean canRecycled() {
-    return (!isFixed() || !isSticky()) && getAttrs().canRecycled();
-  }
-
-  /**
-   * Sets the offset for the sticky
-   *
-   * @param stickyOffset child[y]-parent[y]
-   */
-  public void setStickyOffset(int stickyOffset) {
-    mStickyOffset = stickyOffset;
-  }
-
-  /**
-   * For now, this method respect the result of {@link WXSDKInstance#isLayerTypeEnabled()}
-   *
-   * @return Refer {@link WXSDKInstance#isLayerTypeEnabled()}
-   */
-  public boolean isLayerTypeEnabled() {
-    return getInstance().isLayerTypeEnabled();
-  }
-
-  /**
-   * Sets whether or not to relayout page during animation, default is false
-   */
-  public void setNeedLayoutOnAnimation(boolean need) {
-    this.mNeedLayoutOnAnimation = need;
-  }
-
-  /**
-   * Trigger a updateStyles invoke to relayout current page
-   */
-  public void notifyNativeSizeChanged(int w, int h) {
-    if (!mNeedLayoutOnAnimation) {
-      return;
-    }
-
-    final WXBridgeManager manager = WXBridgeManager.getInstance();
-    manager.setStyleWidth(getInstanceId(), getRef(), w);
-    manager.setStyleHeight(getInstanceId(), getRef(), h);
-  }
-
-  public static final int STATE_DOM_FINISH = 0;
-  public static final int STATE_UI_FINISH = 1;
-  public static final int STATE_ALL_FINISH = 2;
-  @IntDef({STATE_DOM_FINISH, STATE_UI_FINISH, STATE_ALL_FINISH})
-  @Retention(RetentionPolicy.SOURCE)
-  @Target(ElementType.PARAMETER)
-  public @interface RenderState {
-  }
-
-  @CallSuper
-  public void onRenderFinish(@RenderState int state) {
-    if (WXTracing.isAvailable()) {
-      double uiTime = Stopwatch.nanosToMillis(mTraceInfo.uiThreadNanos);
-      if (state == STATE_ALL_FINISH || state == STATE_DOM_FINISH) {
-        WXTracing.TraceEvent domEvent = WXTracing.newEvent("DomExecute", getInstanceId(), mTraceInfo.rootEventId);
-        domEvent.ph = "X";
-        domEvent.ts = mTraceInfo.domThreadStart;
-        domEvent.tname = "DOMThread";
-        domEvent.name = getComponentType();
-        domEvent.classname = getClass().getSimpleName();
-        if (getParent() != null) {
-          domEvent.parentRef = getParent().getRef();
-        }
-        domEvent.submit();
-      }
-
-      if (state == STATE_ALL_FINISH || state == STATE_UI_FINISH) {
-        if (mTraceInfo.uiThreadStart != -1) {
-          WXTracing.TraceEvent uiEvent = WXTracing.newEvent("UIExecute", getInstanceId(), mTraceInfo.rootEventId);
-          uiEvent.ph = "X";
-          uiEvent.duration = uiTime;
-          uiEvent.ts = mTraceInfo.uiThreadStart;
-          uiEvent.name = getComponentType();
-          uiEvent.classname = getClass().getSimpleName();
-          if (getParent() != null) {
-            uiEvent.parentRef = getParent().getRef();
-          }
-          uiEvent.submit();
-        } else {
-          if (WXEnvironment.isApkDebugable() && !isLazy()) {
-//            WXLogUtils.w("onRenderFinish", "createView() not called");
-          }
-        }
-      }
-    }
-  }
-
-  protected boolean isRippleEnabled() {
-    try {
-      Object obj = getAttrs().get(Constants.Name.RIPPLE_ENABLED);
-      return WXUtils.getBoolean(obj, false);
-    } catch (Throwable t) {
-      //ignore
-    }
-    return false;
-  }
-
-  public boolean isWaste() {
-    return waste;
-  }
-
-  /**
-   * mark node waste,
-   * if node is waster should hidden, and dom tree should allow not show
-   * */
-  public void setWaste(boolean waste) {
-    if(this.waste != waste){
-      this.waste = waste;
-      if(!WXBasicComponentType.RECYCLE_LIST.equals(getParent().getComponentType())){
-          NativeRenderObjectUtils.nativeRenderObjectChildWaste(getRenderObjectPtr(), waste);
-      }
-
-     if(waste){
-        //update dom not show, and put style to hidden
-        getStyles().put(Constants.Name.VISIBILITY, Constants.Value.HIDDEN);
-        //if component not init, mark lazy init when use, reduce view count
-        if(getHostView() == null){
-          if(!mLazy){
-            lazy(true);
-          }
-        }else{
-          getHostView().setVisibility(View.GONE);
-        }
-      }else{
-       getStyles().put(Constants.Name.VISIBILITY, Constants.Value.VISIBLE);
-        if(getHostView() == null){
-          if(mLazy) { // when parent is lazy just mark node lazy false
-            if(mParent != null && mParent.isLazy()){
-              lazy(false);
-            }else{
-              Statements.initLazyComponent(this, mParent);
-            }
-          }
-        }else{
-          getHostView().setVisibility(View.VISIBLE);
-        }
-      }
-    }
-  }
-
-
-  /** component uniquie key id in native for recycle-list,
-   *  should be unique for every native component differ with ref
-   *  */
-  public  String getViewTreeKey(){
-    if(mViewTreeKey == null){
-      if(getParent() == null){
-        mViewTreeKey = hashCode() + "_" + getRef();
-      }else{
-        mViewTreeKey = hashCode() + "_" + getRef() + "_" + getParent().indexOf(this);
-      }
-    }
-    return mViewTreeKey;
-  }
-
-  private String mViewTreeKey;
-
-  public WXTransition getTransition() {
-    return mTransition;
-  }
-
-  public void setTransition(WXTransition transition) {
-    this.mTransition = transition;
-  }
-
-  public void addAnimationForElement(Map<String, Object> animMap) {
-    if(animMap!=null && !animMap.isEmpty()){
-      if(animations == null){
-        animations = new ConcurrentLinkedQueue<>();
-      }
-      animations.add(new Pair<>(getRef(),animMap));
-    }
-  }
-
-  private void parseAnimation() {
-    if (null == animations) {
-      return;
-    }
-    for (final Pair<String, Map<String, Object>> pair : animations) {
-      if (!TextUtils.isEmpty(pair.first)) {
-        final WXAnimationBean animationBean = createAnimationBean(pair.first, pair.second);
-        if (animationBean != null) {
-          GraphicActionAnimation action = new GraphicActionAnimation(getInstance(), getRef(), animationBean);
-          action.executeAction();
-        }
-      }
-    }
-    animations.clear();
-  }
-
-
-  private WXAnimationBean createAnimationBean(String ref,Map<String, Object> style){
-    if (style != null) {
-      try {
-        Object transform = style.get(Constants.Name.TRANSFORM);
-        if (transform instanceof String && !TextUtils.isEmpty((String) transform)) {
-          String transformOrigin = (String) style.get(Constants.Name.TRANSFORM_ORIGIN);
-          WXAnimationBean animationBean = new WXAnimationBean();
-          int width = (int) getLayoutWidth();
-          int height = (int) getLayoutHeight();
-          animationBean.styles = new WXAnimationBean.Style();
-          animationBean.styles.init(transformOrigin, (String) transform, width, height,WXSDKManager.getInstanceViewPortWidth(getInstanceId()),
-                  getInstance());
-          return animationBean;
-        }
-      }catch (RuntimeException e){
-        WXLogUtils.e("", e);
-        return null;
-      }
-    }
-    return null;
-  }
-
-  /**
-   * node is lazy
-   * */
-  private boolean mLazy = false;
-
-  /***/
-  public void lazy(boolean lazy) {
-    mLazy = lazy;
-  }
-
-  public long getRenderObjectPtr(){
-    if(getBasicComponentData().isRenderPtrEmpty()){
-      getBasicComponentData().setRenderObjectPr(NativeRenderObjectUtils.nativeGetRenderObject(getInstanceId(), getRef()));
-    }
-    return getBasicComponentData().getRenderObjectPr();
-  }
-
-
-  public void updateNativeAttr(String key, Object value){
-    if(key == null){
-      return;
-    }
-    if(value == null){
-      value  = "";
-    }
-    getBasicComponentData().getAttrs().put(key, value);
-    NativeRenderObjectUtils.nativeUpdateRenderObjectAttr(getRenderObjectPtr(), key, value.toString());
-  }
-
-  public  void  nativeUpdateAttrs(Map<String, Object> dynamic){
-    Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
-    /**
-     * diff attrs, see attrs has update, remove none update attrs
-     * */
-    Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
-    while (iterator.hasNext()){
-      Map.Entry<String, Object> objectEntry = iterator.next();
-      if(objectEntry.getKey() == null){
-        continue;
-      }
-      updateNativeAttr(objectEntry.getKey(), objectEntry.getValue());
-    }
-  }
-
-
-  public void updateNativeStyle(String key, Object value){
-    if(key == null){
-      return;
-    }
-    if(value == null){
-      value  = "";
-    }
-    getBasicComponentData().getStyles().put(key, value);
-    NativeRenderObjectUtils.nativeUpdateRenderObjectStyle(getRenderObjectPtr(), key, value.toString());
-  }
-
-  public  void  updateNativeStyles(Map<String, Object> dynamic){
-    Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
-    /**
-     * diff attrs, see attrs has update, remove none update attrs
-     * */
-    Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
-    while (iterator.hasNext()){
-      Map.Entry<String, Object> objectEntry = iterator.next();
-      if(objectEntry.getKey() == null){
-        continue;
-      }
-      updateNativeStyle(objectEntry.getKey(), objectEntry.getValue());
-    }
-  }
-
-  public void addLayerOverFlowListener(String ref) {
-    if (getInstance() != null)
-      getInstance().addLayerOverFlowListener(ref);
-  }
-
-  public void removeLayerOverFlowListener(String ref) {
-    if (getInstance() != null)
-      getInstance().removeLayerOverFlowListener(ref);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponentFactory.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponentFactory.java
deleted file mode 100644
index ce3b986..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponentFactory.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.text.TextUtils;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.ui.IFComponentHolder;
-import com.taobao.weex.ui.WXComponentRegistry;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Component factory
- */
-public class WXComponentFactory {
-
-  public static WXComponent newInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    if (instance == null || TextUtils.isEmpty(basicComponentData.mComponentType)) {
-      return null;
-    }
-
-    IFComponentHolder holder = WXComponentRegistry.getComponent(basicComponentData.mComponentType);
-    if (holder == null) {
-      if (WXEnvironment.isApkDebugable()) {
-        String tag = "WXComponentFactory error type:[" +
-                basicComponentData.mComponentType + "]" + " class not found";
-        WXLogUtils.e(tag);
-      }
-      //For compatible reason of JS framework, unregistered type will be treated as container.
-      holder = WXComponentRegistry.getComponent(WXBasicComponentType.CONTAINER);
-      if (holder == null) {
-        WXExceptionUtils.commitCriticalExceptionRT(instance.getInstanceId(),
-                WXErrorCode.WX_RENDER_ERR_COMPONENT_NOT_REGISTER, "createComponent",
-                basicComponentData.mComponentType + " not registered", null);
-        return null;
-      }
-    }
-
-    try {
-      return holder.createInstance(instance, parent, basicComponentData);
-    } catch (Throwable e) {
-      WXLogUtils.e("WXComponentFactory Exception type:[" + basicComponentData.mComponentType + "] ", e);
-    }
-
-    return null;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponentProp.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponentProp.java
deleted file mode 100644
index 65b9b51..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponentProp.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface WXComponentProp {
-
-  String name();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java
deleted file mode 100644
index c4fbbab..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.flat.FlatComponent;
-import com.taobao.weex.ui.flat.WidgetContainer;
-import com.taobao.weex.ui.flat.widget.WidgetGroup;
-import com.taobao.weex.ui.view.WXFrameLayout;
-import com.taobao.weex.utils.WXUtils;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.LinkedList;
-
-/**
- * div component
- */
-@Component(lazyload = false)
-public class WXDiv extends WidgetContainer<WXFrameLayout> implements FlatComponent<WidgetGroup> {
-
-  private WidgetGroup mWidgetGroup;
-
-  public static class Ceator implements ComponentCreator {
-    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      return new WXDiv(instance, parent, basicComponentData);
-    }
-  }
-
-  @Deprecated
-  public WXDiv(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXDiv(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  @Override
-  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
-    WXFrameLayout frameLayout = new WXFrameLayout(context);
-    frameLayout.holdComponent(this);
-    return frameLayout;
-  }
-
-  @Override
-  public boolean promoteToView(boolean checkAncestor) {
-    if (null != getInstance().getFlatUIContext()) {
-      return !intendToBeFlatContainer() ||
-            getInstance().getFlatUIContext().promoteToView(this, checkAncestor, WXDiv.class);
-    }
-    return false;
-  }
-
-  /**
-   * Create View tree there. Either this method or {@link #createViewImpl()} get called.
-   * If this object will be promoted to view, then getOrCreateFlatWidget() should never be called.
-   */
-  @Override
-  @NonNull
-  public WidgetGroup getOrCreateFlatWidget() {
-    if (mWidgetGroup == null) {
-      mWidgetGroup = new WidgetGroup(getInstance().getFlatUIContext());
-      for (int i = 0; i < getChildCount(); i++) {
-        createChildViewAt(i);
-      }
-      mountFlatGUI();
-    }
-    return mWidgetGroup;
-  }
-
-  @Override
-  protected void mountFlatGUI() {
-    if(widgets == null){
-      widgets = new LinkedList<>();
-    }
-    if (promoteToView(true)) {
-      if(getHostView()!=null) {
-        getHostView().mountFlatGUI(widgets);
-      }
-    } else {
-      mWidgetGroup.replaceAll(widgets);
-    }
-  }
-
-  @Override
-  public void unmountFlatGUI() {
-    if (getHostView() != null) {
-      getHostView().unmountFlatGUI();
-    }
-  }
-
-  @Override
-  public boolean intendToBeFlatContainer() {
-    return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXDiv.class.equals(getClass());
-  }
-
-  @Override
-  public boolean isVirtualComponent() {
-    return !promoteToView(true);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java
deleted file mode 100644
index b95c8a0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.annotation.SuppressLint;
-import android.text.TextUtils;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.webkit.WebView;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.taobao.weex.R;
-import com.taobao.weex.IWXRenderListener;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.OnWXScrollListener;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.instance.InstanceOnFireEventInterceptor;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.ArrayDeque;
-import java.util.Comparator;
-import java.util.Map;
-import java.util.PriorityQueue;
-import java.util.Queue;
-
-@Component(lazyload = false)
-public class WXEmbed extends WXDiv implements WXSDKInstance.OnInstanceVisibleListener,NestedContainer {
-
-  public static final  String STRATEGY_NONE =  "none";
-  public static final  String STRATEGY_NORMAL =  "normal";
-  public static final  String STRATEGY_HIGH =  "high";
-
-
-  public static final  String PRIORITY_LOW =  "low";
-  public static final  String PRIORITY_NORMAL =  "normal";
-  public static final  String PRIORITY_HIGH =  "high";
-
-  public static final String ITEM_ID = "itemId";
-
-  private String src;
-  protected WXSDKInstance mNestedInstance;
-  private static int ERROR_IMG_WIDTH = (int) WXViewUtils.getRealPxByWidth(270,750);
-  private static int ERROR_IMG_HEIGHT = (int) WXViewUtils.getRealPxByWidth(260,750);
-
-  private boolean mIsVisible = true;
-  private EmbedRenderListener mListener;
-  private EmbedInstanceOnScrollFireEventInterceptor mInstanceOnScrollFireEventInterceptor;
-
-
-  private String priority = PRIORITY_NORMAL;
-
-  private String strategy = "normal";  //none, normal, high(ignore priority)
-
-  private long hiddenTime;
-
-
-
-  public interface EmbedManager {
-    WXEmbed getEmbed(String itemId);
-    void putEmbed(String itemId,WXEmbed comp);
-  }
-
-  public static class FailToH5Listener extends ClickToReloadListener {
-    @SuppressLint("SetJavaScriptEnabled")
-    @Override
-    public void onException(NestedContainer comp, String errCode, String msg) {
-      //downgrade embed
-      if( errCode != null && comp instanceof WXEmbed && errCode.startsWith("1|")) {
-        ViewGroup container = comp.getViewContainer();
-        WebView webView = new WebView(container.getContext());
-        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-        webView.setLayoutParams(params);
-        webView.getSettings().setJavaScriptEnabled(true);
-
-        //WebView Remote Code Execution Vulnerability
-        webView.removeJavascriptInterface("searchBoxJavaBridge_");
-        webView.removeJavascriptInterface("accessibility");
-        webView.removeJavascriptInterface("accessibilityTraversal");
-        webView.getSettings().setSavePassword(false);
-
-        container.removeAllViews();
-        container.addView(webView);
-        webView.loadUrl(((WXEmbed) comp).src);
-      }else{
-        super.onException(comp,errCode,msg);
-      }
-    }
-  }
-
-  /**
-   * Default event listener.
-   */
-  public static class ClickToReloadListener implements OnNestedInstanceEventListener {
-    @Override
-    public void onException(NestedContainer container, String errCode, String msg) {
-      if (TextUtils.equals(errCode, WXErrorCode.
-              WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode()) && container instanceof WXEmbed) {
-        final WXEmbed comp = ((WXEmbed)container);
-        final ImageView imageView = new ImageView(comp.getContext());
-        imageView.setImageResource(R.drawable.weex_error);
-        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ERROR_IMG_WIDTH, ERROR_IMG_HEIGHT);
-        layoutParams.gravity = Gravity.CENTER;
-        imageView.setLayoutParams(layoutParams);
-        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
-        imageView.setAdjustViewBounds(true);
-        imageView.setOnClickListener(new View.OnClickListener() {
-          @Override
-          public void onClick(View v) {
-            imageView.setOnClickListener(null);
-            imageView.setEnabled(false);
-            comp.loadContent();
-          }
-        });
-        FrameLayout hostView = comp.getHostView();
-        hostView.removeAllViews();
-        hostView.addView(imageView);
-        WXLogUtils.e("WXEmbed", "NetWork failure :" + errCode + ",\n error message :" + msg);
-      }
-    }
-
-    @Override
-    public boolean onPreCreate(NestedContainer comp, String src) {
-      return true;
-    }
-
-    @Override
-    public String transformUrl(String origin) {
-      return origin;
-    }
-
-    @Override
-    public void onCreated(NestedContainer comp, WXSDKInstance nestedInstance) {
-
-    }
-  }
-
-  static class EmbedRenderListener implements IWXRenderListener {
-    WXEmbed mComponent;
-    OnNestedInstanceEventListener mEventListener;
-
-    EmbedRenderListener(WXEmbed comp) {
-      mComponent = comp;
-      mEventListener = new ClickToReloadListener();
-    }
-
-    @Override
-    public void onViewCreated(WXSDKInstance instance, View view) {
-      FrameLayout hostView = mComponent.getHostView();
-      hostView.removeAllViews();
-      hostView.addView(view);
-    }
-
-    @Override
-    public void onRenderSuccess(WXSDKInstance instance, int width, int height) {
-
-    }
-
-    @Override
-    public void onRefreshSuccess(WXSDKInstance instance, int width, int height) {
-
-    }
-
-    @Override
-    public void onException(WXSDKInstance instance, String errCode, String msg) {
-      if (mEventListener != null) {
-        mEventListener.onException(mComponent, errCode, msg);
-      }
-    }
-  }
-
-  @Deprecated
-  public WXEmbed(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXEmbed(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-    mListener = new EmbedRenderListener(this);
-    mInstanceOnScrollFireEventInterceptor = new EmbedInstanceOnScrollFireEventInterceptor(this);
-
-    ERROR_IMG_WIDTH = (int) WXViewUtils.getRealPxByWidth(270, instance.getInstanceViewPortWidth());
-    ERROR_IMG_HEIGHT = (int) WXViewUtils.getRealPxByWidth(260, instance.getInstanceViewPortWidth());
-    if (instance instanceof EmbedManager) {
-      Object itemId = getAttrs().get(ITEM_ID);
-      if (itemId != null) {
-        ((EmbedManager) instance).putEmbed(itemId.toString(), this);
-      }
-    }
-    this.priority = WXUtils.getString(getAttrs().get(Constants.Name.PRIORITY), PRIORITY_NORMAL);
-    this.strategy = WXUtils.getString(getAttrs().get(Constants.Name.STRATEGY), STRATEGY_NONE);
-    instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_EMBED_COUNT,1);
-  }
-
-  @Override
-  public void setOnNestEventListener(OnNestedInstanceEventListener listener){
-    mListener.mEventListener = listener;
-  }
-
-  @Override
-  public ViewGroup getViewContainer() {
-    return getHostView();
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.SRC:
-        String src = WXUtils.getString(param, null);
-        if (src != null)
-          setSrc(src);
-        return true;
-      case Constants.Name.PRIORITY:
-        String priority = WXUtils.getString(param, null);
-        if (priority != null) {
-          setPriority(priority);
-        }
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @Override
-  public void renderNewURL(String url) {
-    src = url;
-    loadContent();
-  }
-
-  @Override
-  public void reload() {
-    if (!TextUtils.isEmpty(src)) {
-      loadContent();
-    }
-  }
-
-  public String getOriginUrl() {
-    return originUrl;
-  }
-
-  public void setOriginUrl(String originUrl) {
-    this.originUrl = originUrl;
-  }
-
-  private String originUrl;
-
-
-  @Override
-  public void addEvent(String type) {
-    super.addEvent(type);
-    if(Constants.Event.SCROLL_START.equals(type)){
-      mInstanceOnScrollFireEventInterceptor.addInterceptEvent(type);
-    }else if(Constants.Event.SCROLL_END.equals(type)){
-      mInstanceOnScrollFireEventInterceptor.addInterceptEvent(type);
-    }else if(Constants.Event.SCROLL.equals(type)){
-      mInstanceOnScrollFireEventInterceptor.addInterceptEvent(type);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SRC)
-  public void setSrc(String src) {
-    originUrl=src;
-    this.src = src;
-    if (mNestedInstance != null) {
-      mNestedInstance.destroy();
-      mNestedInstance = null;
-    }
-    if (mIsVisible && !TextUtils.isEmpty(this.src)) {
-      loadContent();
-    }
-  }
-  public String getSrc() {
-    return src;
-  }
-
-
-  @WXComponentProp(name = Constants.Name.PRIORITY)
-  public void setPriority(String priority) {
-    if(TextUtils.isEmpty(priority)){
-      return;
-    }
-    this.priority = priority;
-  }
-
-  /**
-   * Load embed content, default behavior is create a nested instance.
-   */
-  protected void loadContent(){
-    if(mNestedInstance != null){
-      mNestedInstance.destroy();
-    }
-    mNestedInstance = createInstance();
-    if(mListener != null && mListener.mEventListener != null){
-      if(!mListener.mEventListener.onPreCreate(this,src)){
-        //cancel render
-        mListener.mEventListener.onCreated(this, mNestedInstance);
-      }
-    }
-  }
-
-  private static final int getLevel(WXEmbed embed){
-    String priority = embed.priority;
-    String strategy = embed.strategy;
-    int level  = 5;
-    if(!STRATEGY_HIGH.equals(strategy)) {
-      if (TextUtils.equals(priority, PRIORITY_LOW)) {
-        level = 0;
-      } else if (TextUtils.equals(priority, PRIORITY_HIGH)) {
-        level = 10;
-      }
-    }
-    return  level;
-  }
-
-  private WXSDKInstance createInstance() {
-    WXSDKInstance sdkInstance = getInstance().createNestedInstance(this);
-    sdkInstance.setParentInstance(getInstance());
-    boolean needsAdd = !getAttrs().containsKey("disableInstanceVisibleListener");
-    if(needsAdd){ //prevent switch off fire viewappear event twice
-        getInstance().addOnInstanceVisibleListener(this);
-    }
-    sdkInstance.registerRenderListener(mListener);
-    mInstanceOnScrollFireEventInterceptor.resetFirstLaterScroller();;
-    sdkInstance.addInstanceOnFireEventInterceptor(mInstanceOnScrollFireEventInterceptor);
-    sdkInstance.registerOnWXScrollListener(mInstanceOnScrollFireEventInterceptor);
-
-    String url=src;
-    if(mListener != null && mListener.mEventListener != null){
-      url=mListener.mEventListener.transformUrl(src);
-      if(!mListener.mEventListener.onPreCreate(this,src)){
-        //cancel render
-        return null;
-      }
-    }
-
-    if(TextUtils.isEmpty(url)){
-      mListener.mEventListener.onException(this,
-              WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode(),
-              WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorMsg() + "!!wx embed src url is null"
-      );
-      return sdkInstance;
-    }
-    sdkInstance.setContainerInfo(WXInstanceApm.KEY_PAGE_PROPERTIES_INSTANCE_TYPE,"embed");
-    sdkInstance.setContainerInfo(WXInstanceApm.KEY_PAGE_PROPERTIES_PARENT_PAGE,getInstance().getWXPerformance().pageName);
-    sdkInstance.renderByUrl(url,
-            url,
-            null, null,
-            WXRenderStrategy.APPEND_ASYNC);
-
-    return sdkInstance;
-  }
-
-  @Override
-  public void setVisibility(String visibility) {
-    super.setVisibility(visibility);
-    boolean visible = TextUtils.equals(visibility, Constants.Value.VISIBLE);
-    if(mIsVisible != visible){
-
-      if (!TextUtils.isEmpty(src) && visible) {
-        if (mNestedInstance == null) {
-          loadContent();
-        } else {
-          mNestedInstance.onViewAppear();
-        }
-      }
-
-      if (!visible) {
-        if (mNestedInstance != null) {
-          mNestedInstance.onViewDisappear();
-        }
-      }
-      mIsVisible = visible;
-      doAutoEmbedMemoryStrategy();
-    }
-  }
-
-  @Override
-  public void destroy() {
-    super.destroy();
-    destoryNestInstance();
-    src = null;
-    if (getInstance() != null) {
-      getInstance().removeOnInstanceVisibleListener(this);
-    }
-  }
-
-  private void  doAutoEmbedMemoryStrategy(){
-    /**
-     * auto manage embed amount in current instance, save memory
-     * */
-    if(!STRATEGY_NONE.equals(this.strategy)){
-      if(!mIsVisible && mNestedInstance != null){
-        if(PRIORITY_LOW.equals(this.priority)){
-          destoryNestInstance();
-        }else{
-          if(getInstance().hiddenEmbeds == null){ // low is in front, when priority is same, hidden time pre in first
-            getInstance().hiddenEmbeds = new PriorityQueue<>(8, new Comparator<WXEmbed>() {
-              @Override
-              public int compare(WXEmbed o1, WXEmbed o2) {
-                int level =  getLevel(o1) - getLevel(o2);
-                if(level != 0){
-                  return  level;
-                }
-                return (int) (o1.hiddenTime - o2.hiddenTime);
-              }
-            });
-          }
-          //getInstance().hiddenEmbeds.remove(this);
-          if(!getInstance().hiddenEmbeds.contains(this)) {
-            this.hiddenTime = System.currentTimeMillis();
-            getInstance().hiddenEmbeds.add(this);
-          }
-          if(getInstance().hiddenEmbeds != null && getInstance().getMaxHiddenEmbedsNum() >= 0){
-            while (getInstance().hiddenEmbeds.size() > getInstance().getMaxHiddenEmbedsNum()){
-              WXEmbed embed = getInstance().hiddenEmbeds.poll();
-              if(embed.mIsVisible){
-                continue;
-              }
-              if(embed != null) {
-                embed.destoryNestInstance();
-              }
-            }
-          }
-        }
-      }
-      if(mIsVisible && mNestedInstance != null){
-        if(getInstance().hiddenEmbeds != null && getInstance().hiddenEmbeds.contains(this)){
-          getInstance().hiddenEmbeds.remove(this);
-        }
-      }
-    }
-
-  }
-
-  @Override
-  public void onAppear() {
-    //appear event from root instance will not trigger visibility change
-    if(mIsVisible && mNestedInstance != null){
-      WXComponent comp = mNestedInstance.getRootComponent();
-      if(comp != null)
-        comp.fireEvent(Constants.Event.VIEWAPPEAR);
-    }
-  }
-
-  @Override
-  public void onDisappear() {
-    //appear event from root instance will not trigger visibility change
-    if(mIsVisible && mNestedInstance != null){
-      WXComponent comp = mNestedInstance.getRootComponent();
-      if(comp != null)
-        comp.fireEvent(Constants.Event.VIEWDISAPPEAR);
-    }
-  }
-
-  @Override
-  public void onActivityStart() {
-    super.onActivityStart();
-    if (mNestedInstance != null) {
-      mNestedInstance.onActivityStart();
-    }
-  }
-
-  @Override
-  public void onActivityResume() {
-    super.onActivityResume();
-    if (mNestedInstance != null) {
-      mNestedInstance.onActivityResume();
-    }
-  }
-
-  @Override
-  public void onActivityPause() {
-    super.onActivityPause();
-    if (mNestedInstance != null) {
-      mNestedInstance.onActivityPause();
-    }
-  }
-
-  @Override
-  public void onActivityStop() {
-    super.onActivityStop();
-    if (mNestedInstance != null) {
-      mNestedInstance.onActivityStop();
-    }
-  }
-
-  @Override
-  public void onActivityDestroy() {
-    super.onActivityDestroy();
-    if (mNestedInstance != null) {
-      mNestedInstance.onActivityDestroy();
-    }
-  }
-
-  public void setStrategy(String strategy) {
-    this.strategy = strategy;
-  }
-
-  private void destoryNestInstance(){
-    if(getInstance().hiddenEmbeds != null && getInstance().hiddenEmbeds.contains(this)){
-      getInstance().hiddenEmbeds.remove(this);
-    }
-    if (mNestedInstance != null) {
-      mNestedInstance.destroy();
-      mNestedInstance = null;
-    }
-    if(WXEnvironment.isApkDebugable()){
-      WXLogUtils.w("WXEmbed destoryNestInstance priority " + priority + " index " + getAttrs().get("index")
-              + "  " + hiddenTime  + " embeds size " + (getInstance().hiddenEmbeds == null ?  0 : getInstance().hiddenEmbeds.size())
-              + " strategy " + this.strategy);
-    }
-  }
-
-  @Override
-  public void addLayerOverFlowListener(String ref) {
-    if (mNestedInstance != null)
-      mNestedInstance.addLayerOverFlowListener(getRef());
-  }
-
-  @Override
-  public void removeLayerOverFlowListener(String ref) {
-    if (mNestedInstance != null)
-      mNestedInstance.removeLayerOverFlowListener(ref);
-  }
-
-  static class EmbedInstanceOnScrollFireEventInterceptor extends InstanceOnFireEventInterceptor implements OnWXScrollListener{
-
-    private WXEmbed mEmbed;
-    private WXComponent firstLayerScroller;
-
-    public EmbedInstanceOnScrollFireEventInterceptor(WXEmbed embed) {
-      this.mEmbed = embed;
-    }
-
-    public void resetFirstLaterScroller(){
-      firstLayerScroller = null;
-    }
-
-    @Override
-    public void onFireEvent(String instanceId, String elementRef, String type, Map<String, Object> params, Map<String, Object> domChanges) {
-      if(mEmbed == null
-              || mEmbed.mNestedInstance == null
-              || !mEmbed.mNestedInstance.getInstanceId().equals(instanceId)){
-        return;
-      }
-      if(firstLayerScroller == null){
-          initFirstLayerScroller();
-      }
-      if(firstLayerScroller == null){
-        return;
-      }
-      if(firstLayerScroller.getRef().equals(elementRef)){
-         mEmbed.getInstance().fireEvent(mEmbed.getRef(), type, params, domChanges);
-      }
-    }
-
-
-    private void initFirstLayerScroller(){
-      if(firstLayerScroller == null){
-          firstLayerScroller = findFirstLayerScroller();
-          if(firstLayerScroller != null){
-            for(String event : getListenEvents()){
-              if(!firstLayerScroller.containsEvent(event)){
-                  firstLayerScroller.getEvents().add(event);
-                  firstLayerScroller.addEvent(event);
-              }
-            }
-          }
-      }
-    }
-
-    /**
-     * get first layer scroller ref
-     * */
-    private WXComponent findFirstLayerScroller(){
-         if(mEmbed.mNestedInstance == null){
-           return null;
-         }
-         WXComponent rootComponent = mEmbed.mNestedInstance.getRootComponent();
-        if(rootComponent instanceof  Scrollable){
-          return rootComponent;
-        }
-        Queue<WXComponent> queues = new ArrayDeque<>();
-        queues.offer(rootComponent);
-        while (!queues.isEmpty()){
-             WXComponent component = queues.poll();
-             if(component == null){
-               break;
-             }
-             if(component instanceof  Scrollable){
-                return  component;
-             }
-             if(component instanceof WXVContainer){
-               WXVContainer container = (WXVContainer) component;
-               for(int i=0; i<container.getChildCount(); i++){
-                  queues.offer(container.getChild(i));
-               }
-             }
-        }
-        return null;
-    }
-
-
-    @Override
-    public void onScrolled(View view, int x, int y) {
-      if(firstLayerScroller != null){
-        return;
-      }
-      if(getListenEvents().size() > 0){
-        initFirstLayerScroller();
-      }
-    }
-
-    @Override
-    public void onScrollStateChanged(View view, int x, int y, int newState) {
-
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXHeader.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXHeader.java
deleted file mode 100644
index a07f628..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXHeader.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.list.WXCell;
-
-/**
- * The same as sticky cell
- */
-@Component(lazyload = false)
-public class WXHeader extends WXCell {
-
-  @Deprecated
-  public WXHeader(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  public WXHeader(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
-    super(instance, parent, lazy, basicComponentData);
-    String parantType = parent.getComponentType();
-    if(WXBasicComponentType.LIST.equals(parantType)
-            || WXBasicComponentType.RECYCLE_LIST.equals(parantType)){
-      getStyles().put(Constants.Name.POSITION, Constants.Value.STICKY);
-      setSticky(Constants.Value.STICKY);
-    }
-  }
-
-  @Override
-  public boolean isLazy() {
-    return false;
-  }
-
-  @Override
-  public boolean canRecycled() {
-    return !isSticky();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXImage.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXImage.java
deleted file mode 100644
index f165e1c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXImage.java
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import com.taobao.weex.dom.WXImageQuality;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import android.Manifest;
-import android.app.Activity;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.text.TextUtils;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.adapter.IWXImgLoaderAdapter;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXImageSharpen;
-import com.taobao.weex.common.WXImageStrategy;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.performance.WXAnalyzerDataTransfer;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXImageView;
-import com.taobao.weex.ui.view.border.BorderDrawable;
-import com.taobao.weex.utils.ImageDrawable;
-import com.taobao.weex.utils.ImgURIUtil;
-import com.taobao.weex.utils.SingleFunctionParser;
-import com.taobao.weex.utils.WXDomUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewToImageUtil;
-import com.taobao.weex.utils.WXViewUtils;
-
-/**
- * Image component
- */
-@Component(lazyload = false)
-public class WXImage extends WXComponent<ImageView> {
-
-  public static final String SUCCEED = "success";
-  public static final String ERRORDESC = "errorDesc";
-  private static final int WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 0x2;
-
-  private String mSrc;
-  private int mBlurRadius;
-  private boolean mAutoRecycle = true;
-
-  private static SingleFunctionParser.FlatMapper<Integer> BLUR_RADIUS_MAPPER = new SingleFunctionParser.FlatMapper<Integer>() {
-    @Override
-    public Integer map(String raw) {
-      return WXUtils.getInteger(raw,0);
-    }
-  };
-
-  public static class Creator implements ComponentCreator {
-    @Override
-    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      return new WXImage(instance, parent, basicComponentData);
-    }
-  }
-
-  @Deprecated
-  public WXImage(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXImage(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  @Override
-  protected ImageView initComponentHostView(@NonNull Context context) {
-    WXImageView view = new WXImageView(context);
-    view.setScaleType(ScaleType.FIT_XY);
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-      view.setCropToPadding(true);
-    }
-    view.holdComponent(this);
-    return view;
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.RESIZE_MODE:
-        String resizeMode = WXUtils.getString(param, null);
-        if (resizeMode != null) { setResizeMode(resizeMode); }
-        return true;
-      case Constants.Name.RESIZE:
-        String resize = WXUtils.getString(param, null);
-        if (resize != null) { setResize(resize); }
-        return true;
-      case Constants.Name.SRC:
-        String src = WXUtils.getString(param, null);
-        if (src != null) { setSrc(src); }
-        return true;
-      case Constants.Name.IMAGE_QUALITY:
-        return true;
-      case Constants.Name.AUTO_RECYCLE:
-        mAutoRecycle = WXUtils.getBoolean(param, mAutoRecycle);
-        if (!mAutoRecycle && null != getInstance()){
-          getInstance().getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_UN_RECYCLE_NUM,1);
-        }
-        return true;
-      case Constants.Name.FILTER:
-        int blurRadius = 0;
-        if (param != null && param instanceof String) {
-          blurRadius = parseBlurRadius((String)param);
-        }
-        if (!TextUtils.isEmpty(this.mSrc)) {
-          setBlurRadius(this.mSrc, blurRadius);
-        }
-        return true;
-      default:
-        return super.setProperty(key, param);
-    }
-  }
-
-  @Override
-  public void refreshData(WXComponent component) {
-    super.refreshData(component);
-    if (component instanceof WXImage) {
-      setSrc(component.getAttrs().getImageSrc());
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.RESIZE_MODE)
-  public void setResizeMode(String resizeMode) {
-    (getHostView()).setScaleType(getResizeMode(resizeMode));
-    getHostView().setImageDrawable(getHostView().getDrawable());
-  }
-
-  @RestrictTo(Scope.LIBRARY_GROUP)
-  protected ScaleType getResizeMode(String resizeMode) {
-    ScaleType scaleType = ScaleType.FIT_XY;
-    if (TextUtils.isEmpty(resizeMode)) {
-      return scaleType;
-    }
-
-    switch (resizeMode) {
-      case "cover":
-        scaleType = ScaleType.CENTER_CROP;
-        break;
-      case "contain":
-        scaleType = ScaleType.FIT_CENTER;
-        break;
-      case "stretch":
-        scaleType = ScaleType.FIT_XY;
-        break;
-      default:
-        break;
-    }
-    return scaleType;
-  }
-
-  @WXComponentProp(name = Constants.Name.RESIZE)
-  public void setResize(String resize) {
-    setResizeMode(resize);
-  }
-
-  /**
-   * Process local scheme, load drawable.
-   * @param rewrited
-   */
-  private void setLocalSrc(Uri rewrited) {
-    ImageView imageView;
-    Drawable localDrawable = ImgURIUtil.getDrawableFromLoaclSrc(getContext(), rewrited);
-    if (localDrawable != null && (imageView = getHostView()) != null) {
-      imageView.setImageDrawable(localDrawable);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SRC)
-  public void setSrc(String src) {
-
-    if (getInstance().getImageNetworkHandler() != null) {
-      String localUrl = getInstance().getImageNetworkHandler().fetchLocal(src);
-      if (!TextUtils.isEmpty(localUrl)) {
-        src = localUrl;
-      }
-    }
-
-    if (src == null) {
-      return;
-    }
-
-    ImageView image = getHostView();
-    if("".equals(src) && image != null){
-      image.setImageDrawable(null);
-      return;
-    }
-
-    if(image != null){
-      if(image.getDrawable() != null && !TextUtils.equals(mSrc, src)){
-        image.setImageDrawable(null);
-      }
-    }
-
-
-    this.mSrc = src;
-    WXSDKInstance instance = getInstance();
-    Uri rewrited = instance.rewriteUri(Uri.parse(src), URIAdapter.IMAGE);
-
-    if (Constants.Scheme.LOCAL.equals(rewrited.getScheme())) {
-      setLocalSrc(rewrited);
-    } else {
-      int blur = 0;
-      String blurStr = getStyles().getBlur();
-      blur = parseBlurRadius(blurStr);
-      setRemoteSrc(rewrited, blur);
-    }
-  }
-
-  private void setBlurRadius(@NonNull String src, int blurRadius) {
-    if(getInstance() != null && blurRadius != mBlurRadius) {
-      Uri parsedUri = getInstance().rewriteUri(Uri.parse(src), URIAdapter.IMAGE);
-      if(!Constants.Scheme.LOCAL.equals(parsedUri.getScheme())) {
-        setRemoteSrc(parsedUri,blurRadius);
-      }
-    }
-  }
-
-  private int parseBlurRadius(@Nullable String rawRadius) {
-    if(rawRadius == null) {
-      return 0;
-    }
-    SingleFunctionParser<Integer> parser = new SingleFunctionParser<Integer>(rawRadius,BLUR_RADIUS_MAPPER);
-    List<Integer> list = null;
-    try {
-      list = parser.parse("blur");
-    }catch (Exception e) {
-      return 0;
-    }
-    if(list == null || list.isEmpty()) {
-      return 0;
-    }
-    return list.get(0);
-  }
-
-  @Override
-  public void recycled() {
-    super.recycled();
-
-    if (getInstance().getImgLoaderAdapter() != null) {
-      getInstance().getImgLoaderAdapter().setImage(null, mHost,
-              null, null);
-    } else {
-      if (WXEnvironment.isApkDebugable()) {
-        throw new WXRuntimeException("getImgLoaderAdapter() == null");
-      }
-      WXLogUtils.e("Error getImgLoaderAdapter() == null");
-    }
-  }
-
-  public void autoReleaseImage(){
-    if(mAutoRecycle){
-      if(getHostView() != null){
-        if (getInstance().getImgLoaderAdapter() != null) {
-          getInstance().getImgLoaderAdapter().setImage(null, mHost, null, null);
-        }
-      }
-    }
-  }
-
-  public void autoRecoverImage() {
-    if(mAutoRecycle) {
-      setSrc(mSrc);
-    }
-  }
-
-  private void setRemoteSrc(Uri rewrited, int blurRadius) {
-
-    WXImageStrategy imageStrategy = new WXImageStrategy(getInstanceId());
-    imageStrategy.isClipping = true;
-
-    WXImageSharpen imageSharpen = getAttrs().getImageSharpen();
-    imageStrategy.isSharpen = imageSharpen == WXImageSharpen.SHARPEN;
-
-    imageStrategy.blurRadius = Math.max(0, blurRadius);
-    this.mBlurRadius = blurRadius;
-
-    final String rewritedStr = rewrited.toString();
-    imageStrategy.setImageListener(new MyImageListener(this,rewritedStr));
-
-    String placeholder=null;
-    if(getAttrs().containsKey(Constants.Name.PLACEHOLDER)){
-      placeholder= (String) getAttrs().get(Constants.Name.PLACEHOLDER);
-    }else if(getAttrs().containsKey(Constants.Name.PLACE_HOLDER)){
-      placeholder=(String)getAttrs().get(Constants.Name.PLACE_HOLDER);
-    }
-    if(placeholder!=null){
-      imageStrategy.placeHolder = getInstance().rewriteUri(Uri.parse(placeholder),URIAdapter.IMAGE).toString();
-    }
-
-    imageStrategy.instanceId = getInstanceId();
-    IWXImgLoaderAdapter imgLoaderAdapter = getInstance().getImgLoaderAdapter();
-    if (imgLoaderAdapter != null) {
-      imgLoaderAdapter.setImage(rewritedStr, getHostView(),
-          getImageQuality(), imageStrategy);
-    }
-  }
-
-  @RestrictTo(Scope.LIBRARY_GROUP)
-  protected WXImageQuality getImageQuality(){
-    return getAttrs().getImageQuality();
-  }
-
-  @Override
-  protected void onFinishLayout() {
-    super.onFinishLayout();
-    updateBorderRadius();
-  }
-
-  @Override
-  public void updateProperties(Map<String, Object> props) {
-    super.updateProperties(props);
-    updateBorderRadius();
-  }
-
-  private void updateBorderRadius() {
-    if (getHostView() instanceof WXImageView) {
-      final WXImageView imageView = (WXImageView)getHostView();
-      BorderDrawable borderDrawable = WXViewUtils.getBorderDrawable(getHostView());
-      float[] borderRadius;
-      if (borderDrawable != null) {
-        RectF borderBox = new RectF(0, 0, WXDomUtils.getContentWidth(this), WXDomUtils.getContentHeight(this));
-        borderRadius = borderDrawable.getBorderInnerRadius(borderBox);
-      } else {
-        borderRadius = new float[] {0, 0, 0, 0, 0, 0, 0, 0};
-      }
-      imageView.setBorderRadius(borderRadius);
-
-      if (imageView.getDrawable() instanceof ImageDrawable) {
-        ImageDrawable imageDrawable = (ImageDrawable)imageView.getDrawable();
-        float[] previousRadius = imageDrawable.getCornerRadii();
-        if (!Arrays.equals(previousRadius, borderRadius)) {
-          imageDrawable.setCornerRadii(borderRadius);
-        }
-      }
-    }
-  }
-
-  /**
-   * Need permission {android.permission.WRITE_EXTERNAL_STORAGE}
-   */
-  @JSMethod(uiThread = false)
-  public void save(final JSCallback saveStatuCallback) {
-
-    if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
-      if (getContext() instanceof Activity) {
-        ActivityCompat.requestPermissions((Activity) getContext(),
-                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
-      }
-    }
-
-    if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
-      if (saveStatuCallback != null) {
-        Map<String, Object> result = new HashMap<>();
-        result.put(SUCCEED, false);
-        result.put(ERRORDESC,"Permission denied: android.permission.WRITE_EXTERNAL_STORAGE");
-        saveStatuCallback.invoke(result);
-      }
-      return;
-    }
-
-    if (mHost == null) {
-      if (saveStatuCallback != null) {
-        Map<String, Object> result = new HashMap<>();
-        result.put(SUCCEED, false);
-        result.put(ERRORDESC,"Image component not initialized");
-        saveStatuCallback.invoke(result);
-      }
-      return;
-    }
-
-    if (mSrc == null || mSrc.equals("")) {
-      if (saveStatuCallback != null) {
-        Map<String, Object> result = new HashMap<>();
-        result.put(SUCCEED, false);
-        result.put(ERRORDESC,"Image does not have the correct src");
-        saveStatuCallback.invoke(result);
-      }
-      return;
-    }
-
-    WXViewToImageUtil.generateImage(mHost, 0, 0xfff8f8f8, new WXViewToImageUtil.OnImageSavedCallback() {
-      @Override
-      public void onSaveSucceed(String path) {
-        if (saveStatuCallback != null) {
-          Map<String, Object> result = new HashMap<>();
-          result.put(SUCCEED, true);
-          saveStatuCallback.invoke(result);
-        }
-      }
-
-      @Override
-      public void onSaveFailed(String errorDesc) {
-        if (saveStatuCallback != null) {
-          Map<String, Object> result = new HashMap<>();
-          result.put(SUCCEED, false);
-          result.put(ERRORDESC,errorDesc);
-          saveStatuCallback.invoke(result);
-        }
-      }
-    });
-  }
-
-  private String preImgUrlStr = "";
-  private void monitorImgSize(ImageView imageView,String currentImgUrlStr){
-    if (null == imageView){
-      return;
-    }
-    WXSDKInstance instance = getInstance();
-    if (null == instance){
-      return;
-    }
-    ViewGroup.LayoutParams params =imageView.getLayoutParams();
-    Drawable img = imageView.getDrawable();
-    if (null == params || null ==img){
-      return;
-    }
-    int imgHeight = img.getIntrinsicHeight();
-    int imgWidth = img.getIntrinsicWidth();
-    if (!preImgUrlStr.equals(currentImgUrlStr)){
-      preImgUrlStr = currentImgUrlStr;
-      if (imgHeight > 1081 && imgWidth > 721){
-        instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_LARGE_IMG_COUNT,1);
-        if (WXAnalyzerDataTransfer.isOpenPerformance){
-          WXAnalyzerDataTransfer.transferPerformance(getInstanceId(),"details",WXInstanceApm.KEY_PAGE_STATS_LARGE_IMG_COUNT,
-              imgWidth+"*"+imgHeight+","+currentImgUrlStr
-              );
-        }
-      }
-      long imgSize = imgHeight * imgWidth;
-      long viewSize = imageView.getMeasuredHeight() * imageView.getMeasuredWidth();
-      if (viewSize == 0){
-          return;
-      }
-      double scaleSize =  imgSize/(double)viewSize;
-      //max diff 40*40
-      if (scaleSize >1.2 && imgSize-viewSize > 1600){
-        instance.getWXPerformance().wrongImgSizeCount++;
-        instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT,1);
-
-        if (WXAnalyzerDataTransfer.isOpenPerformance){
-          WXAnalyzerDataTransfer.transferPerformance(getInstanceId(),"details",WXInstanceApm.KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT,
-              String.format(Locale.ROOT, "imgSize:[%d,%d],viewSize:[%d,%d],urL:%s",imgWidth,imgHeight,imageView.getMeasuredWidth(),imageView.getMeasuredHeight()
-              ,currentImgUrlStr)
-          );
-        }
-      }
-    }
-
-  }
-
-  @Override
-  public void destroy() {
-    if(getHostView() instanceof WXImageView){
-      if (getInstance().getImgLoaderAdapter() != null) {
-        getInstance().getImgLoaderAdapter().setImage(null, mHost, null, null);
-      }
-    }
-    super.destroy();
-  }
-
-  public interface Measurable {
-    int getNaturalWidth();
-    int getNaturalHeight();
-  }
-
-  public  static class MyImageListener implements WXImageStrategy.ImageListener {
-
-    private WeakReference<WXImage> wxImageWeakReference;
-
-    private String rewritedStr;
-
-    MyImageListener(WXImage image,String rewritedStr) {
-      this.wxImageWeakReference = new WeakReference<WXImage>(image);
-      this.rewritedStr = rewritedStr;
-    }
-
-    @Override
-    public void onImageFinish(String url, ImageView imageView, boolean result, Map extra) {
-      WXImage image = wxImageWeakReference.get();
-
-      if(image == null)
-        return;
-
-      if (image.getEvents().contains(Constants.Event.ONLOAD)) {
-        Map<String, Object> params = new HashMap<String, Object>();
-        Map<String, Object> size = new HashMap<>(2);
-        if (imageView != null && imageView instanceof Measurable) {
-          size.put("naturalWidth", ((Measurable) imageView).getNaturalWidth());
-          size.put("naturalHeight", ((Measurable) imageView).getNaturalHeight());
-        } else {
-          size.put("naturalWidth", 0);
-          size.put("naturalHeight", 0);
-        }
-        if (image.containsEvent(Constants.Event.ONLOAD)) {
-          params.put("success", result);
-          params.put("size", size);
-          image.fireEvent(Constants.Event.ONLOAD, params);
-        }
-      }
-      image.monitorImgSize(imageView,rewritedStr);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXIndicator.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXIndicator.java
deleted file mode 100644
index 449c12e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXIndicator.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXCircleIndicator;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-/**
- *
- * Slider indicator
- */
-@Component(lazyload = false)
-public class WXIndicator extends WXComponent<WXCircleIndicator> {
-
-  @Deprecated
-  public WXIndicator(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  public WXIndicator(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-    super(instance, parent, isLazy, basicComponentData);
-  }
-
-  @Override
-  protected void setHostLayoutParams(WXCircleIndicator host, int width, int height, int left, int right, int top, int bottom) {
-      FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
-      this.setMarginsSupportRTL(params, left, top, right, bottom);
-      host.setLayoutParams(params);
-  }
-
-  @Override
-  protected WXCircleIndicator initComponentHostView(@NonNull Context context) {
-    WXCircleIndicator view = new WXCircleIndicator(context);
-    if (getParent() instanceof WXSlider) {
-      return view;
-    } else {
-      if (WXEnvironment.isApkDebugable()) {
-        throw new WXRuntimeException("WXIndicator initView error.");
-      }
-    }
-    return null;
-  }
-
-  @Override
-  protected void onHostViewInitialized(WXCircleIndicator host) {
-    super.onHostViewInitialized(host);
-    if (getParent() instanceof WXSlider) {
-      ((WXSlider) getParent()).addIndicator(this);
-    }
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.ITEM_COLOR:
-        String item_color = WXUtils.getString(param,null);
-        if (item_color != null)
-          setItemColor(item_color);
-        return true;
-      case Constants.Name.ITEM_SELECTED_COLOR:
-        String selected_color = WXUtils.getString(param,null);
-        if (selected_color != null)
-          setItemSelectedColor(selected_color);
-        return true;
-      case Constants.Name.ITEM_SIZE:
-        Integer item_size = WXUtils.getInteger(param,null);
-        if (item_size != null)
-          setItemSize(item_size);
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-
-  @WXComponentProp(name = Constants.Name.ITEM_COLOR)
-  public void setItemColor(String itemColor) {
-    if (!TextUtils.isEmpty(itemColor)) {
-      int colorInt = WXResourceUtils.getColor(itemColor);
-      if (colorInt != Integer.MIN_VALUE) {
-        getHostView().setPageColor(colorInt);
-        getHostView().forceLayout();
-        getHostView().requestLayout();
-      }
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.ITEM_SELECTED_COLOR)
-  public void setItemSelectedColor(String itemSelectedColor) {
-    if (!TextUtils.isEmpty(itemSelectedColor)) {
-      int colorInt = WXResourceUtils.getColor(itemSelectedColor);
-      if (colorInt != Integer.MIN_VALUE) {
-        getHostView().setFillColor(colorInt);
-        getHostView().forceLayout();
-        getHostView().requestLayout();
-      }
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.ITEM_SIZE)
-  public void setItemSize(int itemSize) {
-    if (itemSize < 0) {
-      return;
-    }
-    getHostView().setRadius(WXViewUtils.getRealPxByWidth(itemSize,getInstance().getInstanceViewPortWidth()) / 2.0f);
-    getHostView().forceLayout();
-    getHostView().requestLayout();
-  }
-
-  public void setShowIndicators(boolean show) {
-    if (getHostView() == null) {
-      return;
-    }
-    if (show) {
-      getHostView().setVisibility(View.VISIBLE);
-    } else {
-      getHostView().setVisibility(View.GONE);
-    }
-  }
-
-  // TODO
-//  public static class IndicatorDomNode extends WXDomObject{
-//    public IndicatorDomNode(){
-//      super();
-//    }
-//
-//    @Override
-//    protected Map<String, String> getDefaultStyle() {
-//      WXStyle pendingStyles = getStyles();
-//      Map<String,String> map = new HashMap<>();
-//      if(!pendingStyles.containsKey(Constants.Name.RIGHT))
-//        map.put(Constants.Name.LEFT,"0");
-//      if(!pendingStyles.containsKey(Constants.Name.BOTTOM))
-//        map.put(Constants.Name.TOP,"0");
-//      return map;
-//    }
-//  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXInput.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXInput.java
deleted file mode 100644
index d1a272d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXInput.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXEditText;
-
-/**
- *
- * Input component
- */
-@Component(lazyload = false)
-public class WXInput extends AbstractEditComponent{
-
-  @Deprecated
-  public WXInput(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  public WXInput(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-    super(instance, parent, isLazy, basicComponentData);
-  }
-
-  @Override
-  protected void appleStyleAfterCreated(WXEditText editText) {
-    super.appleStyleAfterCreated(editText);
-    editText.setSingleLine();//default use single line , same to ios
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXLoading.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXLoading.java
deleted file mode 100644
index 9ddd15a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXLoading.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.list.WXListComponent;
-import com.taobao.weex.ui.view.WXFrameLayout;
-import com.taobao.weex.ui.view.WXLoadingLayout;
-import com.taobao.weex.ui.view.refresh.core.WXSwipeLayout;
-import com.taobao.weex.ui.view.refresh.wrapper.BaseBounceView;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * div component
- */
-@Component(lazyload = false)
-public class WXLoading extends WXBaseRefresh implements WXSwipeLayout.WXOnLoadingListener {
-
-  public static final String HIDE = "hide";
-
-  public WXLoading(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
-    super(instance, parent, lazy, basicComponentData);
-  }
-
-  @Override
-  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
-    return new WXLoadingLayout(context);
-  }
-
-  @Override
-  public void onLoading() {
-    if (getEvents().contains(Constants.Event.ONLOADING)) {
-      fireEvent(Constants.Event.ONLOADING);
-    }
-  }
-
-  @Override
-  protected void setHostLayoutParams(WXFrameLayout host, int width, int height,
-                                     int left, int right, int top, int bottom) {
-    // The view of WXLoading will always be wrapped by a WXRefreshView at some point
-    // which is unknowable for front-end so the margins should always be 0 in LayoutParams,
-    // otherwise it will bring visible layout errors. This means WXLoading do not
-    // support margin.
-    super.setHostLayoutParams(host, width, height, 0, 0, 0, 0);
-  }
-
-  @Override
-  public void onPullingUp(float dy, int pullOutDistance, float viewHeight) {
-    if (getEvents().contains(Constants.Event.ONPULLING_UP)) {
-      Map<String, Object> data = new HashMap<>();
-      data.put(Constants.Name.DISTANCE_Y, dy);
-      data.put(Constants.Name.PULLING_DISTANCE, pullOutDistance);
-      data.put(Constants.Name.VIEW_HEIGHT, viewHeight);
-      fireEvent(Constants.Event.ONPULLING_UP, data);
-    }
-  }
-
-  @Override
-  public boolean canRecycled() {
-    return false;
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.DISPLAY:
-        String display = WXUtils.getString(param,null);
-        if (display != null)
-          setDisplay(display);
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @WXComponentProp(name = Constants.Name.DISPLAY)
-  public void setDisplay(String display) {
-    if (!TextUtils.isEmpty(display)) {
-      if (display.equals(HIDE)) {
-        if (getParent() instanceof WXListComponent || getParent() instanceof WXScroller) {
-          if (((BaseBounceView)getParent().getHostView()).getSwipeLayout().isRefreshing()) {
-            ((BaseBounceView) getParent().getHostView()).finishPullLoad();
-            ((BaseBounceView) getParent().getHostView()).onLoadmoreComplete();
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXLoadingIndicator.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXLoadingIndicator.java
deleted file mode 100644
index be6bdd1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXLoadingIndicator.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.graphics.Color;
-
-import android.support.annotation.NonNull;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.refresh.circlebar.CircleProgressBar;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-
-@Component(lazyload = false)
-
-public class WXLoadingIndicator extends WXComponent<CircleProgressBar> {
-
-
-    public WXLoadingIndicator(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-        super(instance, parent, isLazy, basicComponentData);
-    }
-
-    @Override
-    protected CircleProgressBar initComponentHostView(@NonNull Context context) {
-        return new CircleProgressBar(context);
-    }
-
-    @Override
-    protected boolean setProperty(String key, Object param) {
-        switch (key) {
-            case Constants.Name.COLOR:
-                String color = WXUtils.getString(param,null);
-                if (color != null)
-                    setColor(color);
-                return true;
-            case Constants.Name.ANIMATING:
-                Boolean result = WXUtils.getBoolean(param, null);
-                if (result != null) {
-                    setAnimating(result);
-                }
-                return true;
-        }
-        return super.setProperty(key, param);
-    }
-
-    @WXComponentProp(name = Constants.Name.COLOR)
-    public void setColor(String color) {
-        if (color != null && !color.equals("")) {
-            int parseColor = WXResourceUtils.getColor(color, Color.RED);
-            getHostView().setColorSchemeColors(parseColor);
-        }
-    }
-
-    @WXComponentProp(name = Constants.Name.ANIMATING)
-    public void setAnimating(boolean animating) {
-        if (animating) {
-            getHostView().start();
-        } else {
-            getHostView().stop();
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXRefresh.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXRefresh.java
deleted file mode 100644
index bf8c99c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXRefresh.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.list.WXListComponent;
-import com.taobao.weex.ui.view.WXFrameLayout;
-import com.taobao.weex.ui.view.WXRefreshLayout;
-import com.taobao.weex.ui.view.refresh.core.WXSwipeLayout;
-import com.taobao.weex.ui.view.refresh.wrapper.BaseBounceView;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * div component
- */
-@Component(lazyload = false)
-public class WXRefresh extends WXBaseRefresh implements WXSwipeLayout.WXOnRefreshListener{
-
-  public static final String HIDE = "hide";
-
-  @Deprecated
-  public WXRefresh(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  public WXRefresh(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
-    super(instance, parent, lazy, basicComponentData);
-  }
-
-  @Override
-  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
-    return new WXRefreshLayout(context);
-  }
-
-  @Override
-  public boolean canRecycled() {
-    return false;
-  }
-
-  @Override
-  public void onRefresh() {
-    if(isDestoryed()){
-      return;
-    }
-    
-    if (getEvents().contains(Constants.Event.ONREFRESH)) {
-      fireEvent(Constants.Event.ONREFRESH);
-    }
-  }
-
-  @Override
-  public int getLayoutTopOffsetForSibling() {
-    //offset siblings
-    return getParent() instanceof Scrollable ? -Math.round(getLayoutHeight()) : 0;
-  }
-
-  @Override
-  public void onPullingDown(float dy, int pullOutDistance, float viewHeight) {
-    if (getEvents() != null && getEvents().contains(Constants.Event.ONPULLING_DOWN)) {
-      Map<String, Object> data = new HashMap<>();
-      data.put(Constants.Name.DISTANCE_Y, dy);
-      data.put(Constants.Name.PULLING_DISTANCE, pullOutDistance);
-      data.put(Constants.Name.VIEW_HEIGHT, viewHeight);
-      fireEvent(Constants.Event.ONPULLING_DOWN, data);
-    }
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.DISPLAY:
-        String display = WXUtils.getString(param,null);
-        if (display != null)
-          setDisplay(display);
-        return true;
-    }
-    return super.setProperty(key,param);
-  }
-
-  @WXComponentProp(name = Constants.Name.DISPLAY)
-  public void setDisplay(String display) {
-    if (!TextUtils.isEmpty(display)) {
-      if (display.equals(HIDE)) {
-        if (getParent() instanceof WXListComponent || getParent() instanceof WXScroller) {
-          if (((BaseBounceView)getParent().getHostView()).getSwipeLayout().isRefreshing()) {
-            ((BaseBounceView) getParent().getHostView()).finishPullRefresh();
-            ((BaseBounceView) getParent().getHostView()).onRefreshingComplete();
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
deleted file mode 100644
index c460849..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
+++ /dev/null
@@ -1,1048 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.support.v4.view.ViewCompat;
-import android.text.TextUtils;
-import android.view.GestureDetector;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-import android.widget.FrameLayout.LayoutParams;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.ICheckBindingScroller;
-import com.taobao.weex.common.OnWXScrollListener;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.helper.ScrollStartEndHelper;
-import com.taobao.weex.ui.component.helper.WXStickyHelper;
-import com.taobao.weex.ui.view.IWXScroller;
-import com.taobao.weex.ui.view.WXBaseRefreshLayout;
-import com.taobao.weex.ui.view.WXHorizontalScrollView;
-import com.taobao.weex.ui.view.WXScrollView;
-import com.taobao.weex.ui.view.WXScrollView.WXScrollViewListener;
-import com.taobao.weex.ui.view.refresh.wrapper.BaseBounceView;
-import com.taobao.weex.ui.view.refresh.wrapper.BounceScrollerView;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Component for scroller. It also support features like
- * "appear", "disappear" and "sticky"
- */
-@Component(lazyload = false)
-
-public class WXScroller extends WXVContainer<ViewGroup> implements WXScrollViewListener,Scrollable {
-
-  public static final String DIRECTION = "direction";
-  protected int mOrientation = Constants.Orientation.VERTICAL;
-  private List<WXComponent> mRefreshs=new ArrayList<>();
-  /** Use for offset children layout */
-  private int mChildrenLayoutOffset = 0;
-  private boolean mForceLoadmoreNextTime = false;
-  private int mOffsetAccuracy = 10;
-  private Point mLastReport = new Point(-1, -1);
-  private boolean mHasAddScrollEvent = false;
-  private Boolean mIslastDirectionRTL;
-
-  private static final int SWIPE_MIN_DISTANCE = 5;
-  private static final int SWIPE_THRESHOLD_VELOCITY = 300;
-  private int mActiveFeature = 0;
-  /**
-   * scroll start and scroll end event
-   * */
-  private ScrollStartEndHelper mScrollStartEndHelper;
-
-  private GestureDetector mGestureDetector;
-
-  private int pageSize = 0;
-  private boolean pageEnable = false;
-  private boolean mIsHostAttachedToWindow = false;
-  private View.OnAttachStateChangeListener mOnAttachStateChangeListener;
-
-  private boolean mlastDirectionRTL = false;
-
-  public static class Creator implements ComponentCreator {
-    @Override
-    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      // For performance message collection
-      instance.setUseScroller(true);
-      return new WXScroller(instance, parent, basicComponentData);
-    }
-  }
-  /**
-   * Map for storing appear information
-   **/
-  private Map<String,AppearanceHelper> mAppearanceComponents = new HashMap<>();
-
-  /**
-   * Map for storing component that is sticky.
-   **/
-  private Map<String, Map<String, WXComponent>> mStickyMap = new HashMap<>();
-  private FrameLayout mRealView;
-  private FrameLayout mScrollerView;
-
-  private int mContentHeight = 0;
-
-  private WXStickyHelper stickyHelper;
-  private Handler handler=new Handler(Looper.getMainLooper());
-
-  private boolean isScrollable = true;
-
-  @Deprecated
-  public WXScroller(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXScroller(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-    stickyHelper = new WXStickyHelper(this);
-    instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_SCROLLER_NUM,1);
-  }
-
-  /**
-   * @return FrameLayout inner ScrollView
-   */
-  @Override
-  public ViewGroup getRealView() {
-    return mScrollerView;
-  }
-
-
-  @Override
-  public void createViewImpl() {
-    super.createViewImpl();
-    for (int i = 0; i < mRefreshs.size(); i++) {
-      WXComponent component = mRefreshs.get(i);
-      component.createViewImpl();
-      checkRefreshOrLoading(component);
-    }
-  }
-
-  /**
-   * @return ScrollView
-   */
-  public ViewGroup getInnerView() {
-    if(getHostView() == null) {
-      return null;
-    }
-    if (getHostView() instanceof BounceScrollerView) {
-      return ((BounceScrollerView) getHostView()).getInnerView();
-    } else {
-      return getHostView();
-    }
-  }
-
-  @Override
-  public void addEvent(String type) {
-    super.addEvent(type);
-    if (ScrollStartEndHelper.isScrollEvent(type)
-            && getInnerView() != null && !mHasAddScrollEvent) {
-      mHasAddScrollEvent = true;
-      if (getInnerView() instanceof WXScrollView) {
-        ((WXScrollView) getInnerView()).addScrollViewListener(new WXScrollViewListener() {
-          @Override
-          public void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy) {
-            getScrollStartEndHelper().onScrolled(x, y);
-            if(!getEvents().contains(Constants.Event.SCROLL)){
-              return;
-            }
-            if (shouldReport(x, y)) {
-              fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy);
-            }
-          }
-
-          @Override
-          public void onScrollToBottom(WXScrollView scrollView, int x, int y) {
-            //ignore
-          }
-
-          @Override
-          public void onScrollStopped(WXScrollView scrollView, int x, int y) {
-            //ignore
-          }
-
-          @Override
-          public void onScroll(WXScrollView scrollView, int x, int y) {
-            //ignore
-          }
-        });
-      } else if (getInnerView() instanceof WXHorizontalScrollView) {
-        ((WXHorizontalScrollView) getInnerView()).addScrollViewListener(new WXHorizontalScrollView.ScrollViewListener() {
-          @Override
-          public void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy) {
-            getScrollStartEndHelper().onScrolled(x, y);
-            if(!getEvents().contains(Constants.Event.SCROLL)){
-              return;
-            }
-            if (shouldReport(x, y)) {
-              fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy);
-            }
-          }
-        });
-      }
-    }
-  }
-
-  private void fireScrollEvent(Rect contentFrame, int x, int y, int oldx, int oldy) {
-    fireEvent(Constants.Event.SCROLL, getScrollEvent(x, y));
-  }
-
-  public Map<String, Object> getScrollEvent(int x, int y){
-    Rect contentFrame =  new Rect();
-    if (getInnerView() instanceof WXScrollView) {
-      contentFrame = ((WXScrollView) getInnerView()).getContentFrame();
-    }else if (getInnerView() instanceof WXHorizontalScrollView) {
-      contentFrame = ((WXHorizontalScrollView) getInnerView()).getContentFrame();
-    }
-    Map<String, Object> event = new HashMap<>(2);
-    Map<String, Object> contentSize = new HashMap<>(2);
-    Map<String, Object> contentOffset = new HashMap<>(2);
-
-    int viewport = getInstance().getInstanceViewPortWidth();
-
-    contentSize.put(Constants.Name.WIDTH, WXViewUtils.getWebPxByWidth(contentFrame.width(), viewport));
-    contentSize.put(Constants.Name.HEIGHT, WXViewUtils.getWebPxByWidth(contentFrame.height(), viewport));
-
-    contentOffset.put(Constants.Name.X, -WXViewUtils.getWebPxByWidth(x, viewport));
-    contentOffset.put(Constants.Name.Y, -WXViewUtils.getWebPxByWidth(y, viewport));
-
-    event.put(Constants.Name.CONTENT_SIZE, contentSize);
-    event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
-    return  event;
-  }
-
-  private boolean shouldReport(int x, int y) {
-    if (mLastReport.x == -1 && mLastReport.y == -1) {
-      mLastReport.x = x;
-      mLastReport.y = y;
-      return true;
-    }
-
-    if (mOrientation == Constants.Orientation.HORIZONTAL
-            && Math.abs(x - mLastReport.x) >= mOffsetAccuracy) {
-      mLastReport.x = x;
-      mLastReport.y = y;
-      return true;
-    }
-
-    if (mOrientation == Constants.Orientation.VERTICAL
-            && Math.abs(y - mLastReport.y) >= mOffsetAccuracy) {
-      mLastReport.x = x;
-      mLastReport.y = y;
-      return true;
-    }
-
-    return false;
-  }
-
-  /**
-   * Intercept refresh view and loading view
-   */
-  @Override
-  public void addSubView(View child, int index) {
-    if (child == null || mRealView == null) {
-      return;
-    }
-
-    if (child instanceof WXBaseRefreshLayout) {
-      return;
-    }
-
-    int count = mRealView.getChildCount();
-    index = index >= count ? -1 : index;
-    if (index == -1) {
-      mRealView.addView(child);
-    } else {
-      mRealView.addView(child, index);
-    }
-  }
-
-  @Override
-  protected int getChildrenLayoutTopOffset() {
-    if (mChildrenLayoutOffset == 0) {
-      // Child LayoutSize data set after call Layout. So init mChildrenLayoutOffset here
-      final int listSize = mRefreshs.size();
-      if (listSize > 0) {
-        for (int i = 0; i < listSize; i++) {
-          WXComponent child = mRefreshs.get(i);
-          mChildrenLayoutOffset += child.getLayoutTopOffsetForSibling();
-        }
-      }
-    }
-    return mChildrenLayoutOffset;
-  }
-
-  /**
-   * Intercept refresh view and loading view
-   */
-  @Override
-  public void addChild(WXComponent child, int index) {
-    if (child instanceof WXBaseRefresh) {
-      if (checkRefreshOrLoading(child)) {
-        mRefreshs.add(child);
-      }
-    }
-    super.addChild(child, index);
-  }
-
-  /**
-   * Setting refresh view and loading view
-   * @param child the refresh_view or loading_view
-   */
-
-  private boolean checkRefreshOrLoading(final WXComponent child) {
-    boolean result = false;
-    if (child instanceof WXRefresh && getHostView() != null) {
-      ((BaseBounceView) getHostView()).setOnRefreshListener((WXRefresh) child);
-      Runnable runnable = WXThread.secure(new Runnable(){
-        @Override
-        public void run() {
-          ((BaseBounceView) getHostView()).setHeaderView(child);
-        }
-      });
-      handler.postDelayed(runnable,100);
-      result = true;
-    }
-
-    if (child instanceof WXLoading && getHostView() !=null) {
-      ((BaseBounceView) getHostView()).setOnLoadingListener((WXLoading)child);
-      Runnable runnable= WXThread.secure(new Runnable(){
-        @Override
-        public void run() {
-          ((BaseBounceView) getHostView()).setFooterView(child);
-        }
-      });
-      handler.postDelayed(runnable, 100);
-      result = true;
-    }
-    return result;
-  }
-
-  @Override
-  public void remove(WXComponent child,boolean destory) {
-    super.remove(child,destory);
-    if(child instanceof WXLoading){
-      ((BaseBounceView)getHostView()).removeFooterView(child);
-    }else if(child instanceof WXRefresh){
-      ((BaseBounceView)getHostView()).removeHeaderView(child);
-    }
-  }
-
-  @Override
-  public void destroy() {
-    super.destroy();
-    if (mAppearanceComponents != null) {
-      mAppearanceComponents.clear();
-    }
-    if (mStickyMap != null) {
-      mStickyMap.clear();
-    }
-    if (mOnAttachStateChangeListener != null && getInnerView() != null) {
-      getInnerView().removeOnAttachStateChangeListener(mOnAttachStateChangeListener);
-    }
-    if (getInnerView() != null && getInnerView() instanceof IWXScroller) {
-      ((IWXScroller) getInnerView()).destroy();
-    }
-  }
-
-  @SuppressLint("RtlHardcoded")
-  @Override
-  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
-    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-      lp.setMargins(left, top, right, bottom);
-      lp.setMarginStart(left);
-      lp.setMarginEnd(right);
-    } else {
-      if (lp instanceof FrameLayout.LayoutParams) {
-        FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
-        if (isLayoutRTL()) {
-          lp_frameLayout.gravity = Gravity.RIGHT | Gravity.TOP;
-          lp.setMargins(right, top, left, bottom);
-        } else {
-          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
-          lp.setMargins(left, top, right, bottom);
-        }
-      } else {
-        lp.setMargins(left, top, right, bottom);
-      }
-    }
-  }
-
-  @Override
-  public void setLayout(WXComponent component) {
-    if (TextUtils.isEmpty(component.getComponentType())
-            || TextUtils.isEmpty(component.getRef()) || component.getLayoutPosition() == null
-            || component.getLayoutSize() == null) {
-      return;
-    }
-    if (component.getHostView() != null) {
-      int layoutDirection = component.isLayoutRTL() ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
-      ViewCompat.setLayoutDirection(component.getHostView(), layoutDirection);
-    }
-    super.setLayout(component);
-  }
-
-  @Override
-  protected MeasureOutput measure(int width, int height) {
-    MeasureOutput measureOutput = new MeasureOutput();
-    if (this.mOrientation == Constants.Orientation.HORIZONTAL) {
-      int screenW = WXViewUtils.getScreenWidth(WXEnvironment.sApplication);
-      int weexW = WXViewUtils.getWeexWidth(getInstanceId());
-      measureOutput.width = width > (weexW >= screenW ? screenW : weexW) ? FrameLayout.LayoutParams.MATCH_PARENT
-              : width;
-      measureOutput.height = height;
-    } else {
-      int screenH = WXViewUtils.getScreenHeight(WXEnvironment.sApplication);
-      int weexH = WXViewUtils.getWeexHeight(getInstanceId());
-      measureOutput.height = height > (weexH >= screenH ? screenH : weexH) ? FrameLayout.LayoutParams.MATCH_PARENT
-              : height;
-      measureOutput.width = width;
-    }
-    return measureOutput;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  protected ViewGroup initComponentHostView(@NonNull Context context) {
-    String scroll;
-    if (getAttrs().isEmpty()) {
-      scroll = "vertical";
-    } else {
-      scroll = getAttrs().getScrollDirection();
-
-      Object o = getAttrs().get(Constants.Name.PAGE_ENABLED);
-
-      pageEnable = o != null && Boolean.parseBoolean(o.toString());
-
-      Object pageSize = getAttrs().get(Constants.Name.PAGE_SIZE);
-      if (pageSize != null) {
-        float aFloat = WXUtils.getFloat(pageSize);
-
-
-        float realPxByWidth = WXViewUtils.getRealPxByWidth(aFloat, getInstance().getInstanceViewPortWidth());
-        if (realPxByWidth != 0) {
-          this.pageSize = (int) realPxByWidth;
-        }
-      }
-
-    }
-
-    ViewGroup host;
-    if(("horizontal").equals(scroll)){
-      mOrientation = Constants.Orientation.HORIZONTAL;
-      final WXHorizontalScrollView scrollView = new WXHorizontalScrollView(context);
-      mRealView = new FrameLayout(context);
-      scrollView.setScrollViewListener(new WXHorizontalScrollView.ScrollViewListener() {
-        @Override
-        public void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy) {
-          procAppear(x,y,oldx,oldy);
-        }
-      });
-      FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
-              LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-      scrollView.addView(mRealView, layoutParams);
-      scrollView.setHorizontalScrollBarEnabled(false);
-      mScrollerView = scrollView;
-      final WXScroller component = this;
-      final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
-        @Override
-        public void onLayoutChange(View view, final int left, int top, final int right, int bottom, final int oldLeft, int oldTop, final int oldRight, int oldBottom) {
-          final View frameLayout = view;
-          scrollView.post(new Runnable() {
-            @Override
-            public void run() {
-              if (mIslastDirectionRTL != null && isLayoutRTL() != mIslastDirectionRTL) {
-                // when layout direction changed we need convert x to RTL x for scroll to the same item
-                int currentX = getScrollX();
-                int totalWidth = getInnerView().getChildAt(0).getWidth();
-                int displayWidth = getInnerView().getMeasuredWidth();
-                scrollView.scrollTo(totalWidth - currentX - displayWidth, component.getScrollY());
-              } else if (isLayoutRTL()) {
-                // if layout direction not changed, but width changede, we need keep RTL offset
-                int oldWidth = oldRight - oldLeft;
-                int width = right - left;
-                int changedWidth = width - oldWidth;
-                if (changedWidth != 0) {
-                  scrollView.scrollBy(changedWidth, component.getScrollY());
-                }
-              }
-              mIslastDirectionRTL = isLayoutRTL();
-            }
-          });
-        }
-      };
-      mRealView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
-        @Override
-        public void onViewAttachedToWindow(View view) {
-          view.addOnLayoutChangeListener(listener);
-        }
-
-        @Override
-        public void onViewDetachedFromWindow(View view) {
-          view.removeOnLayoutChangeListener(listener);
-        }
-      });
-
-
-      if(pageEnable) {
-        mGestureDetector = new GestureDetector(new MyGestureDetector(scrollView));
-        scrollView.setOnTouchListener(new View.OnTouchListener() {
-          @Override
-          public boolean onTouch(View v, MotionEvent event) {
-            if (pageSize == 0)  {
-              pageSize = v.getMeasuredWidth();
-            }
-
-            if (mGestureDetector.onTouchEvent(event)) {
-              return true;
-            }
-            else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL ){
-              int scrollX = getScrollX();
-              int featureWidth = pageSize;
-              mActiveFeature = ((scrollX + (featureWidth/2))/featureWidth);
-              int scrollTo = mActiveFeature*featureWidth;
-              scrollView.smoothScrollTo(scrollTo, 0);
-              return true;
-            }
-            else{
-              return false;
-            }
-          }
-        });
-      }
-
-
-      host = scrollView;
-    }else{
-      mOrientation = Constants.Orientation.VERTICAL;
-      BounceScrollerView scrollerView = new BounceScrollerView(context, mOrientation, this);
-      mRealView = new FrameLayout(context);
-      WXScrollView innerView = scrollerView.getInnerView();
-      innerView.addScrollViewListener(this);
-      FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
-              LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-      mScrollerView = innerView;
-      innerView.addView(mRealView, layoutParams);
-      innerView.setVerticalScrollBarEnabled(true);
-      innerView.setNestedScrollingEnabled(WXUtils.getBoolean(getAttrs().get(Constants.Name.NEST_SCROLLING_ENABLED), true));
-      innerView.addScrollViewListener(new WXScrollViewListener() {
-        @Override
-        public void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy) {
-
-        }
-
-        @Override
-        public void onScrollToBottom(WXScrollView scrollView, int x, int y) {
-
-        }
-
-        @Override
-        public void onScrollStopped(WXScrollView scrollView, int x, int y) {
-          List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
-          if(listeners!=null && listeners.size()>0){
-            for (OnWXScrollListener listener : listeners) {
-              if (listener != null) {
-                listener.onScrollStateChanged(scrollView,x,y,OnWXScrollListener.IDLE);
-              }
-            }
-          }
-          getScrollStartEndHelper().onScrollStateChanged(OnWXScrollListener.IDLE);
-        }
-
-        @Override
-        public void onScroll(WXScrollView scrollView, int x, int y) {
-          List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
-          if(listeners!=null && listeners.size()>0){
-            for (OnWXScrollListener listener : listeners) {
-              if (listener != null) {
-                if(listener instanceof ICheckBindingScroller){
-                  if(((ICheckBindingScroller) listener).isNeedScroller(getRef(),null)){
-                    listener.onScrolled(scrollView, x, y);
-                  }
-                }else {
-                  listener.onScrolled(scrollView, x, y);
-                }
-              }
-            }
-          }
-        }
-      });
-      host = scrollerView;
-    }
-
-    host.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
-      @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-      @Override
-      public void onGlobalLayout() {
-        procAppear(0,0,0,0);
-        View view;
-        if( (view = getHostView()) == null){
-          return;
-        }
-        if(Build.VERSION.SDK_INT >=  Build.VERSION_CODES.JELLY_BEAN) {
-          view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
-        }else{
-          view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
-        }
-      }
-    });
-    mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
-      @Override
-      public void onViewAttachedToWindow(View v) {
-        mIsHostAttachedToWindow = true;
-        procAppear(getScrollX(), getScrollY(), getScrollX(), getScrollY());
-      }
-
-      @Override
-      public void onViewDetachedFromWindow(View v) {
-        mIsHostAttachedToWindow = false;
-        dispatchDisappearEvent();
-      }
-    };
-    host.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
-    return host;
-  }
-
-  @Override
-  public int getScrollY() {
-    return getInnerView() == null ? 0 : getInnerView().getScrollY();
-  }
-
-  @Override
-  public int getScrollX() {
-    return getInnerView() == null ? 0 : getInnerView().getScrollX();
-  }
-
-  @Override
-  public int getOrientation() {
-    return mOrientation;
-  }
-
-  public Map<String, Map<String, WXComponent>> getStickMap() {
-    return mStickyMap;
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.SHOW_SCROLLBAR:
-        Boolean result = WXUtils.getBoolean(param,null);
-        if (result != null) {
-          setShowScrollbar(result);
-        }
-        return true;
-      case Constants.Name.SCROLLABLE:
-        boolean scrollable = WXUtils.getBoolean(param, true);
-        setScrollable(scrollable);
-        return true;
-      case Constants.Name.OFFSET_ACCURACY:
-        int accuracy = WXUtils.getInteger(param, 10);
-        setOffsetAccuracy(accuracy);
-        return true;
-        default:
-          break;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @WXComponentProp(name = Constants.Name.SHOW_SCROLLBAR)
-  public void setShowScrollbar(boolean show) {
-    if(getInnerView()==null){
-      return;
-    }
-    if (mOrientation == Constants.Orientation.VERTICAL) {
-      getInnerView().setVerticalScrollBarEnabled(show);
-    } else {
-      getInnerView().setHorizontalScrollBarEnabled(show);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SCROLLABLE)
-  public void setScrollable(boolean scrollable) {
-    this.isScrollable = scrollable;
-    View hostView = getInnerView();
-    if(hostView instanceof WXHorizontalScrollView) {
-      ((WXHorizontalScrollView)hostView).setScrollable(scrollable);
-    }else if(hostView instanceof WXScrollView) {
-      ((WXScrollView)hostView).setScrollable(scrollable);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.OFFSET_ACCURACY)
-  public void setOffsetAccuracy(int accuracy) {
-    float realPx = WXViewUtils.getRealPxByWidth(accuracy, getInstance().getInstanceViewPortWidth());
-    this.mOffsetAccuracy = (int) realPx;
-  }
-
-  @Override
-  public boolean isScrollable() {
-    return isScrollable;
-  }
-
-
-  @Override
-  public void bindStickStyle(WXComponent component) {
-    stickyHelper.bindStickStyle(component,mStickyMap);
-  }
-
-  @Override
-  public void unbindStickStyle(WXComponent component) {
-    stickyHelper.unbindStickStyle(component,mStickyMap);
-  }
-
-  /**
-   * Bind appear event
-   */
-  @Override
-  public void bindAppearEvent(WXComponent component) {
-    setWatch(AppearanceHelper.APPEAR,component,true);
-  }
-
-  private void setWatch(int event,WXComponent component,boolean isWatch){
-    AppearanceHelper item = mAppearanceComponents.get(component.getRef());
-    if (item == null) {
-      item = new AppearanceHelper(component);
-      mAppearanceComponents.put(component.getRef(),item);
-    }
-
-    item.setWatchEvent(event,isWatch);
-
-    //check current components appearance status.
-    procAppear(0,0,0,0);
-  }
-
-  /**
-   * Bind disappear event
-   */
-  @Override
-  public void bindDisappearEvent(WXComponent component) {
-    setWatch(AppearanceHelper.DISAPPEAR,component,true);
-  }
-
-  /**
-   * Remove appear event
-   */
-  @Override
-  public void unbindAppearEvent(WXComponent component) {
-    setWatch(AppearanceHelper.APPEAR,component,false);
-  }
-
-  /**
-   * Remove disappear event
-   */
-  @Override
-  public void unbindDisappearEvent(WXComponent component) {
-    setWatch(AppearanceHelper.DISAPPEAR,component,false);
-  }
-
-  @Override
-  public void scrollTo(WXComponent component, Map<String, Object> options) {
-    float offsetFloat = 0;
-    boolean smooth = true;
-
-    if (options != null) {
-      String offset = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
-      smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
-      if (offset != null) {
-        try {
-          offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offset), getInstance().getInstanceViewPortWidth());
-        }catch (Exception e ){
-          WXLogUtils.e("Float parseFloat error :"+e.getMessage());
-        }
-      }
-    }
-
-    if(pageEnable) {
-      mActiveFeature = mChildren.indexOf(component);
-    }
-
-    int viewYInScroller = component.getAbsoluteY() - getAbsoluteY();
-    int viewXInScroller = 0;
-    if (this.isLayoutRTL()) {
-      // if layout direction is rtl, we need calculate rtl scroll x;
-      if (component.getParent() != null && component.getParent() == this) {
-        if (getInnerView().getChildCount() > 0) {
-          int totalWidth = getInnerView().getChildAt(0).getWidth();
-          int displayWidth = getInnerView().getMeasuredWidth();
-          viewXInScroller = totalWidth - (component.getAbsoluteX() - getAbsoluteX()) - displayWidth;
-        } else {
-          viewXInScroller = component.getAbsoluteX() - getAbsoluteX();
-        }
-      } else {
-        int displayWidth = getInnerView().getMeasuredWidth();
-        viewXInScroller = component.getAbsoluteX() - getAbsoluteX() - displayWidth + (int)component.getLayoutWidth();
-      }
-      offsetFloat = -offsetFloat;
-    } else {
-      viewXInScroller = component.getAbsoluteX() - getAbsoluteX();
-    }
-    scrollBy(viewXInScroller - getScrollX() + (int) offsetFloat, viewYInScroller - getScrollY() + (int) offsetFloat, smooth);
-
-  }
-
-  /**
-   * Scroll by specified distance. Horizontal scroll is not supported now.
-   * @param x horizontal distance, not support
-   * @param y vertical distance. Negative for scroll to top
-   */
-  public void scrollBy(final int x, final int y) {
-    scrollBy(x, y, false);
-  }
-
-  public void scrollBy(final int x, final int y, final boolean smooth) {
-    if (getInnerView() == null) {
-      return;
-    }
-
-    getInnerView().postDelayed(new Runnable() {
-      @Override
-      public void run() {
-        if (mOrientation == Constants.Orientation.VERTICAL) {
-          if (smooth) {
-            ((WXScrollView) getInnerView()).smoothScrollBy(0, y);
-          } else {
-            ((WXScrollView) getInnerView()).scrollBy(0, y);
-          }
-        } else {
-          if (smooth) {
-            ((WXHorizontalScrollView) getInnerView()).smoothScrollBy(x, 0);
-          } else {
-            ((WXHorizontalScrollView) getInnerView()).scrollBy(x, 0);
-          }
-        }
-        getInnerView().invalidate();
-      }
-    }, 16);
-  }
-
-  @Override
-  public void onScrollChanged(WXScrollView scrollView, int x, int y,
-                              int oldx, int oldy) {
-    procAppear( x, y, oldx, oldy);
-  }
-
-  @Override
-  public void notifyAppearStateChange(String wxEventType, String direction) {
-    if (containsEvent(Constants.Event.APPEAR) || containsEvent(Constants.Event.DISAPPEAR)) {
-      Map<String, Object> params = new HashMap<>();
-      params.put("direction", direction);
-      fireEvent(wxEventType, params);
-    }
-    // No-op. The moment to notify children is decided by the time when scroller is attached
-    // or detached to window. Do not call super as scrollview has different disposal.
-  }
-
-  /**
-   * Process event like appear and disappear
-   *
-   * This method will be invoked in several situation below.
-   *    1. bind or unbind event
-   *    2. host view is attached to window
-   *    3. when scrollview is scrolling
-   */
-  private void procAppear(int x, int y, int oldx,
-                          int oldy) {
-    if (!mIsHostAttachedToWindow) return;
-    int moveY = y - oldy;
-    int moveX = x - oldx;
-    String direction = moveY > 0 ? Constants.Value.DIRECTION_UP :
-            moveY < 0 ? Constants.Value.DIRECTION_DOWN : null;
-    if (mOrientation == Constants.Orientation.HORIZONTAL && moveX != 0) {
-      direction = moveX > 0 ? Constants.Value.DIRECTION_RIGHT : Constants.Value.DIRECTION_LEFT;
-    }
-
-    for (Entry<String, AppearanceHelper> item : mAppearanceComponents.entrySet()) {
-      AppearanceHelper helper = item.getValue();
-
-      if (!helper.isWatch()) {
-        continue;
-      }
-      boolean visible = checkItemVisibleInScroller(helper.getAwareChild());
-
-      int result = helper.setAppearStatus(visible);
-      if (result != AppearanceHelper.RESULT_NO_CHANGE) {
-        helper.getAwareChild().notifyAppearStateChange(result == AppearanceHelper.RESULT_APPEAR ? Constants.Event.APPEAR : Constants.Event.DISAPPEAR, direction);
-      }
-    }
-  }
-
-  /**
-   * Check the view of given component is visible in scrollview.
-   *
-   * @param component ready to be check
-   * @return item is visible
-   */
-  private boolean checkItemVisibleInScroller(WXComponent component) {
-    boolean visible = false;
-    while (component != null && !(component instanceof WXScroller)) {
-      if (component.getParent() instanceof WXScroller) {
-        if (mOrientation == Constants.Orientation.HORIZONTAL) {
-          int offsetLeft = (int) component.getLayoutPosition().getLeft() - getScrollX();
-          visible = (offsetLeft > 0 - component.getLayoutWidth() && offsetLeft < getLayoutWidth());
-        } else {
-          int offsetTop = (int) component.getLayoutPosition().getTop() - getScrollY();
-          visible = (offsetTop > 0 - component.getLayoutHeight() && offsetTop < getLayoutHeight());
-        }
-      }
-      component = component.getParent();
-    }
-    return visible;
-  }
-
-  /**
-   * Dispatch disappear event to the child components in need.
-   */
-  private void dispatchDisappearEvent() {
-    for (Entry<String, AppearanceHelper> item : mAppearanceComponents.entrySet()) {
-      AppearanceHelper helper = item.getValue();
-      if (!helper.isWatch()) {
-        continue;
-      }
-      int result = helper.setAppearStatus(false);
-      if (result != AppearanceHelper.RESULT_NO_CHANGE) {
-        helper.getAwareChild().notifyAppearStateChange(result == AppearanceHelper.RESULT_APPEAR ?
-                Constants.Event.APPEAR : Constants.Event.DISAPPEAR, "");
-      }
-    }
-  }
-
-  @Override
-  public void onScrollToBottom(WXScrollView scrollView, int x, int y) {
-
-  }
-
-  @Override
-  public void onScrollStopped(WXScrollView scrollView, int x, int y) {
-  }
-
-  @Override
-  public void onScroll(WXScrollView scrollView, int x, int y) {
-
-    this.onLoadMore(scrollView, x, y);
-  }
-
-  /**
-   * Handle loadMore Event.when Scroller has bind loadMore Event and set the attr of loadMoreOffset
-   * it will tell the JS to handle the event of onLoadMore;
-   * @param scrollView  the WXScrollView
-   * @param x the X direction
-   * @param y the Y direction
-   */
-  protected void onLoadMore(WXScrollView scrollView, int x, int y) {
-    try {
-      String offset = getAttrs().getLoadMoreOffset();
-      if (TextUtils.isEmpty(offset)) {
-        return;
-      }
-      int offsetInt = (int)WXViewUtils.getRealPxByWidth(Float.parseFloat(offset), getInstance().getInstanceViewPortWidth());
-
-      int contentH = scrollView.getChildAt(0).getHeight();
-      int scrollerH = scrollView.getHeight();
-      int offScreenY = contentH - y - scrollerH;
-      if (offScreenY < offsetInt) {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d("[WXScroller-onScroll] offScreenY :" + offScreenY);
-        }
-        if (mContentHeight != contentH || mForceLoadmoreNextTime) {
-          fireEvent(Constants.Event.LOADMORE);
-          mContentHeight = contentH;
-          mForceLoadmoreNextTime = false;
-        }
-      }
-    } catch (Exception e) {
-      WXLogUtils.d("[WXScroller-onScroll] ", e);
-    }
-
-  }
-
-  @JSMethod
-  public void resetLoadmore() {
-    mForceLoadmoreNextTime = true;
-  }
-
-  public ScrollStartEndHelper getScrollStartEndHelper() {
-    if(mScrollStartEndHelper == null){
-      mScrollStartEndHelper = new ScrollStartEndHelper(this);
-    }
-    return mScrollStartEndHelper;
-  }
-
-
-  class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
-    public WXHorizontalScrollView getScrollView() {
-      return scrollView;
-    }
-
-    private final WXHorizontalScrollView scrollView;
-
-    MyGestureDetector(WXHorizontalScrollView horizontalScrollView) {
-      scrollView = horizontalScrollView;
-    }
-
-    @Override
-    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-      int mItems = mChildren.size();
-      try {
-        //right to left
-        if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
-          int featureWidth = pageSize;
-          mActiveFeature = (mActiveFeature < (mItems - 1))? mActiveFeature + 1:mItems -1;
-          scrollView.smoothScrollTo(mActiveFeature*featureWidth, 0);
-          return true;
-        }
-        //left to right
-        else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
-          int featureWidth = pageSize;
-          mActiveFeature = (mActiveFeature > 0)? mActiveFeature - 1:0;
-          scrollView.smoothScrollTo(mActiveFeature*featureWidth, 0);
-          return true;
-        }
-      } catch (Exception e) {
-        WXLogUtils.e("There was an error processing the Fling event:" + e.getMessage());
-      }
-      return false;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java
deleted file mode 100644
index c2806fa..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v4.view.ViewPager;
-import android.support.v4.view.ViewPager.OnPageChangeListener;
-import android.text.TextUtils;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.BaseFrameLayout;
-import com.taobao.weex.ui.view.WXCircleIndicator;
-import com.taobao.weex.ui.view.WXCirclePageAdapter;
-import com.taobao.weex.ui.view.WXCircleViewPager;
-import com.taobao.weex.ui.view.gesture.WXGestureType;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
-
-@Component(lazyload = false)
-
-public class WXSlider extends WXVContainer<FrameLayout> {
-
-  public static final String INDEX = "index";
-  public static final String INFINITE = "infinite";
-
-  private boolean isInfinite = true;
-
-  Map<String, Object> params = new HashMap<>();
-  private float offsetXAccuracy = 0.1f;
-  private int initIndex = -1;
-  private boolean keepIndex = false;
-  private Runnable initRunnable;
-
-
-  public static class Creator implements ComponentCreator {
-    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      return new WXSlider(instance, parent, basicComponentData);
-    }
-  }
-
-  /**
-   * Scrollable sliderview
-   */
-  /**
-   * package
-   **/
-  WXCircleViewPager mViewPager;
-  /**
-   * Circle indicator
-   */
-  protected WXIndicator mIndicator;
-
-  /**
-   * Adapter for sliderview
-   */
-  protected WXCirclePageAdapter mAdapter;
-
-  protected boolean mShowIndicators = true;
-
-  protected OnPageChangeListener mPageChangeListener = new SliderPageChangeListener();
-
-  @Deprecated
-  public WXSlider(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXSlider(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  @Override
-  protected BaseFrameLayout initComponentHostView(@NonNull Context context) {
-    BaseFrameLayout view = new BaseFrameLayout(context);
-    // init view pager
-    if (getAttrs() != null) {
-      Object obj = getAttrs().get(INFINITE);
-      isInfinite = WXUtils.getBoolean(obj, true);
-    }
-    FrameLayout.LayoutParams pagerParams = new FrameLayout.LayoutParams(
-        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-    mViewPager = new WXCircleViewPager(context);
-    mViewPager.setCircle(isInfinite);
-    mViewPager.setLayoutParams(pagerParams);
-
-    // init adapter
-    mAdapter = new WXCirclePageAdapter(isInfinite);
-    mViewPager.setAdapter(mAdapter);
-    // add to parent
-    view.addView(mViewPager);
-    mViewPager.addOnPageChangeListener(mPageChangeListener);
-
-    registerActivityStateListener();
-
-    return view;
-  }
-
-  /**
-   * Slider is not a regular container,top/left/right/bottom not apply to view,expect indicator.
-   */
-  @Override
-  public LayoutParams getChildLayoutParams(WXComponent child,View childView, int width, int height, int left, int right, int top, int bottom) {
-    ViewGroup.LayoutParams lp = childView.getLayoutParams();
-    if (lp == null) {
-      lp = new FrameLayout.LayoutParams(width, height);
-    } else {
-      lp.width = width;
-      lp.height = height;
-    }
-
-    if (lp instanceof ViewGroup.MarginLayoutParams) {
-      //expect indicator .
-      if (child instanceof WXIndicator) {
-        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, left, top, right, bottom);
-      } else {
-        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, 0, 0, 0, 0);
-      }
-    }
-    return lp;
-  }
-
-
-  @Override
-  public void addEvent(String type) {
-    super.addEvent(type);
-    if (Constants.Event.SCROLL.equals(type)) {
-      if (mViewPager == null) {
-        return;
-      }
-      mViewPager.addOnPageChangeListener(new SliderOnScrollListener(this));
-    }
-  }
-
-  @Override
-  public boolean containsGesture(WXGestureType WXGestureType) {
-    //Enable gesture for slider
-    return super.containsGesture(WXGestureType);
-  }
-
-  @Override
-  public ViewGroup getRealView() {
-    return mViewPager;
-  }
-
-  @Override
-  public void addSubView(View view, int index) {
-    if (view == null || mAdapter == null) {
-      return;
-    }
-
-    if (view instanceof WXCircleIndicator) {
-      return;
-    }
-    mAdapter.addPageView(view);
-    hackTwoItemsInfiniteScroll();
-    if (initIndex != -1 && mAdapter.getRealCount() > initIndex) {
-      if(initRunnable == null){
-        initRunnable = new Runnable() {
-          @Override
-          public void run() {
-            initIndex = getInitIndex();
-            mViewPager.setCurrentItem(getRealIndex(initIndex));
-            initIndex = -1;
-            initRunnable = null;
-          }
-        };
-      }
-      mViewPager.removeCallbacks(initRunnable);
-      mViewPager.postDelayed(initRunnable, 50);
-    } else {
-      if (!keepIndex) {
-        mViewPager.setCurrentItem(getRealIndex(0));
-      }
-    }
-    if (mIndicator != null) {
-      mIndicator.getHostView().forceLayout();
-      mIndicator.getHostView().requestLayout();
-    }
-  }
-
-  @Override
-  public void setLayout(WXComponent component) {
-    if (mAdapter != null) {
-      mAdapter.setLayoutDirectionRTL(this.isLayoutRTL());
-    }
-    super.setLayout(component);
-  }
-
-  @Override
-  public void remove(WXComponent child, boolean destroy) {
-    if (child == null || child.getHostView() == null || mAdapter == null) {
-      return;
-    }
-
-    mAdapter.removePageView(child.getHostView());
-    hackTwoItemsInfiniteScroll();
-    super.remove(child,destroy);
-  }
-
-  @Override
-  public void destroy() {
-    super.destroy();
-    if (mViewPager != null) {
-      mViewPager.stopAutoScroll();
-      mViewPager.removeAllViews();
-      mViewPager.destory();
-    }
-  }
-
-  @Override
-  public void onActivityResume() {
-    super.onActivityResume();
-    if (mViewPager != null && mViewPager.isAutoScroll()) {
-      mViewPager.startAutoScroll();
-    }
-  }
-
-  @Override
-  public void onActivityStop() {
-    super.onActivityStop();
-    if (mViewPager != null) {
-      mViewPager.pauseAutoScroll();
-    }
-  }
-
-  public void addIndicator(WXIndicator indicator) {
-    FrameLayout root = getHostView();
-    if (root == null) {
-      return;
-    }
-    mIndicator = indicator;
-    mIndicator.setShowIndicators(mShowIndicators);
-    WXCircleIndicator indicatorView = indicator.getHostView();
-    if (indicatorView != null) {
-      indicatorView.setCircleViewPager(mViewPager);
-      // indicatorView.setOnPageChangeListener(mPageChangeListener);  // commented for twice onChange() called when do slide.
-      root.addView(indicatorView);
-    }
-
-  }
-
-
-  private int getInitIndex(){
-    Object index = getAttrs().get(Constants.Name.INDEX);
-    int select = WXUtils.getInteger(index, initIndex);
-    if(mAdapter == null || mAdapter.getCount() == 0){
-      return  0;
-    }
-    if(select >= mAdapter.getRealCount()){
-      select = select%mAdapter.getRealCount();
-    }
-
-    return select;
-  }
-
-  private int getRealIndex(int idx) {
-    int retIdx = idx;
-
-    if (mAdapter.getRealCount() > 0) {
-      if(idx >= mAdapter.getRealCount()) retIdx = mAdapter.getRealCount() - 1;
-      if (isLayoutRTL()) {
-        retIdx = mAdapter.getRealCount() - 1 - retIdx;
-      }
-    }
-    retIdx = retIdx + 0;
-    return retIdx;
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.VALUE:
-        String value = WXUtils.getString(param, null);
-        if (value != null) {
-          setValue(value);
-        }
-        return true;
-      case Constants.Name.AUTO_PLAY:
-        String aotu_play = WXUtils.getString(param, null);
-        if (aotu_play != null) {
-          setAutoPlay(aotu_play);
-        }
-        return true;
-      case Constants.Name.SHOW_INDICATORS:
-        String indicators = WXUtils.getString(param, null);
-        if (indicators != null) {
-          setShowIndicators(indicators);
-        }
-        return true;
-      case Constants.Name.INTERVAL:
-        Integer interval = WXUtils.getInteger(param, null);
-        if (interval != null) {
-          setInterval(interval);
-        }
-        return true;
-      case Constants.Name.INDEX:
-        Integer index = WXUtils.getInteger(param, null);
-        if (index != null) {
-          setIndex(index);
-        }
-        return true;
-      case Constants.Name.OFFSET_X_ACCURACY:
-        Float accuracy = WXUtils.getFloat(param, 0.1f);
-        if (accuracy != 0) {
-          setOffsetXAccuracy(accuracy);
-        }
-        return true;
-      case Constants.Name.SCROLLABLE:
-        boolean scrollable = WXUtils.getBoolean(param, true);
-        setScrollable(scrollable);
-        return true;
-      case Constants.Name.KEEP_INDEX:
-        this.keepIndex = WXUtils.getBoolean(param, false);
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @Deprecated
-  @WXComponentProp(name = Constants.Name.VALUE)
-  public void setValue(String value) {
-    if (value == null || getHostView() == null) {
-      return;
-    }
-    int i;
-    try {
-      i = Integer.parseInt(value);
-    } catch (NumberFormatException e) {
-      WXLogUtils.e("", e);
-      return;
-    }
-
-    setIndex(i);
-  }
-
-  @WXComponentProp(name = Constants.Name.AUTO_PLAY)
-  public void setAutoPlay(String autoPlay) {
-    if (TextUtils.isEmpty(autoPlay) || autoPlay.equals("false")) {
-      mViewPager.stopAutoScroll();
-    } else {
-      mViewPager.stopAutoScroll();
-      mViewPager.startAutoScroll();
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SHOW_INDICATORS)
-  public void setShowIndicators(String show) {
-    if (TextUtils.isEmpty(show) || show.equals("false")) {
-      mShowIndicators = false;
-    } else {
-      mShowIndicators = true;
-    }
-
-    if (mIndicator == null) {
-      return;
-    }
-    mIndicator.setShowIndicators(mShowIndicators);
-  }
-
-  @WXComponentProp(name = Constants.Name.INTERVAL)
-  public void setInterval(int intervalMS) {
-    if (mViewPager != null && intervalMS > 0) {
-      mViewPager.setIntervalTime(intervalMS);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.INDEX)
-  public void setIndex(int index) {
-    if (mViewPager != null && mAdapter != null) {
-      if (index >= mAdapter.getRealCount() || index < 0) {
-        initIndex = index;
-        return;
-      }
-
-      index = getRealIndex(index);
-      mViewPager.setCurrentItem(index);
-      if (mIndicator != null && mIndicator.getHostView() != null
-              && mIndicator.getHostView().getRealCurrentItem() != index) {
-        //OnPageChangeListener not triggered
-        WXLogUtils.d("setIndex >>>> correction indicator to " + index);
-        mIndicator.getHostView().setRealCurrentItem(index);
-        mIndicator.getHostView().invalidate();
-
-        if (mPageChangeListener != null && mAdapter != null) {
-          mPageChangeListener.onPageSelected(mAdapter.getFirst() + index);
-        }
-      }
-    }
-  }
-  @WXComponentProp(name = Constants.Name.SCROLLABLE)
-  public void setScrollable(boolean scrollable) {
-    if (mViewPager != null && mAdapter != null) {
-      mViewPager.setScrollable(scrollable);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.OFFSET_X_ACCURACY)
-  public void setOffsetXAccuracy(float accuracy) {
-    this.offsetXAccuracy = accuracy;
-  }
-
-  protected class SliderPageChangeListener implements OnPageChangeListener {
-
-    private int lastPos = -1;
-
-    @Override
-    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-
-    }
-
-    @Override
-    public void onPageSelected(int pos) {
-      if (mAdapter.getRealPosition(pos) == lastPos) {
-        return;
-      }
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d("onPageSelected >>>>" + mAdapter.getRealPosition(pos) + " lastPos: " + lastPos);
-      }
-      if (mAdapter == null || mAdapter.getRealCount() == 0) {
-        return;
-      }
-
-      int realPosition = mAdapter.getRealPosition(pos);
-      if (mChildren == null || realPosition >= mChildren.size()) {
-        return;
-      }
-
-      if (getEvents().size() == 0) {
-        return;
-      }
-      WXEvent event = getEvents();
-      String ref = getRef();
-      if (event.contains(Constants.Event.CHANGE) && WXViewUtils.onScreenArea(getHostView())) {
-        params.put(INDEX, realPosition);
-
-        Map<String, Object> domChanges = new HashMap<>();
-        Map<String, Object> attrsChanges = new HashMap<>();
-        attrsChanges.put(INDEX, realPosition);
-        domChanges.put("attrs", attrsChanges);
-        WXSDKManager.getInstance().fireEvent(getInstanceId(), ref,
-            Constants.Event.CHANGE, params, domChanges);
-      }
-
-      mViewPager.requestLayout();
-      getHostView().invalidate();
-      lastPos = mAdapter.getRealPosition(pos);
-    }
-
-    @Override
-    public void onPageScrollStateChanged(int arg0) {
-      FrameLayout root = getHostView();
-      if (null != root) {
-        root.invalidate();
-      }
-    }
-  }
-
-  protected static class SliderOnScrollListener implements OnPageChangeListener {
-    private float lastPositionOffset = 99f;
-    private int selectedPosition;
-    private WXSlider target;
-
-    public SliderOnScrollListener(WXSlider target) {
-      this.target = target;
-      this.selectedPosition = target.mViewPager.superGetCurrentItem();
-    }
-
-    @Override
-    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-      if (lastPositionOffset == 99f) {
-        lastPositionOffset = positionOffset;
-        return;
-      }
-
-      float offset = positionOffset - lastPositionOffset;
-
-      if (Math.abs(offset) >= target.offsetXAccuracy) {
-        if (position == selectedPosition) {
-          //slide to left. positionOffset[0 -> 1]
-          Map<String,Object> event = new HashMap<>(1);
-          event.put(Constants.Name.OFFSET_X_RATIO, -positionOffset);
-          target.fireEvent(Constants.Event.SCROLL, event);
-        } else if (position < selectedPosition) {
-          //slide to right. positionOffset[1 -> 0]
-          Map<String,Object> event = new HashMap<>(1);
-          event.put(Constants.Name.OFFSET_X_RATIO, (1f - positionOffset));
-          target.fireEvent(Constants.Event.SCROLL, event);
-        }
-        lastPositionOffset = positionOffset;
-      }
-    }
-
-    @Override
-    public void onPageSelected(int position) {
-      selectedPosition = position;
-    }
-
-    @Override
-    public void onPageScrollStateChanged(int state) {
-
-      /**
-       * @homeblog@vip.qq.com
-       *
-       *  add scrollstart & scrollend event
-       *
-       */
-      switch (state) {
-        case ViewPager.SCROLL_STATE_IDLE:
-          lastPositionOffset = 99f;
-          target.fireEvent("scrollend");
-          break;
-        case ViewPager.SCROLL_STATE_DRAGGING:
-          target.fireEvent("scrollstart");
-          break;
-        case ViewPager.SCROLL_STATE_SETTLING:
-          break;
-
-      }
-    }
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  private void hackTwoItemsInfiniteScroll() {
-    if (mViewPager == null || mAdapter == null) {
-      return;
-    }
-    if (isInfinite) {
-      if (mAdapter.getRealCount() == 2) {
-        final GestureDetector gestureDetector = new GestureDetector(getContext(), new FlingGestureListener(mViewPager));
-        mViewPager.setOnTouchListener(new View.OnTouchListener() {
-          @Override
-          public boolean onTouch(View v, MotionEvent event) {
-            return gestureDetector.onTouchEvent(event);
-          }
-        });
-      } else {
-        mViewPager.setOnTouchListener(null);
-      }
-    }
-  }
-
-  private static class FlingGestureListener extends GestureDetector.SimpleOnGestureListener {
-    private static final int SWIPE_MIN_DISTANCE = WXViewUtils.dip2px(50);
-    private static final int SWIPE_MAX_OFF_PATH = WXViewUtils.dip2px(250);
-    private static final int SWIPE_THRESHOLD_VELOCITY = WXViewUtils.dip2px(200);
-    private WeakReference<WXCircleViewPager> pagerRef;
-
-    FlingGestureListener(WXCircleViewPager pager) {
-      this.pagerRef = new WeakReference<>(pager);
-    }
-
-    @Override
-    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-      WXCircleViewPager mViewPager = pagerRef.get();
-      if (mViewPager == null) {
-        return false;
-      }
-
-      try {
-        if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
-          return false;
-        }
-
-        if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
-                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
-                && mViewPager.superGetCurrentItem() == 1) {
-          // right to left swipe
-          mViewPager.setCurrentItem(0, false);
-          return true;
-        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
-                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
-                && mViewPager.superGetCurrentItem() == 0) {
-          // left to right swipe
-          mViewPager.setCurrentItem(1, false);
-          return true;
-        }
-      } catch (Exception e) {
-        // ignore
-      }
-      return false;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSliderNeighbor.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSliderNeighbor.java
deleted file mode 100644
index bfcaa4b..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSliderNeighbor.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v4.view.ViewPager;
-import android.text.TextUtils;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.BaseFrameLayout;
-import com.taobao.weex.ui.view.WXCircleIndicator;
-import com.taobao.weex.ui.view.WXCirclePageAdapter;
-import com.taobao.weex.ui.view.WXCircleViewPager;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-
-/**
- * Known Issus: In auto play mode, neighbor view not scaled or aplhaed rarely.
- *
- * Created by xingjiu on 16/8/18.
- */
-public class WXSliderNeighbor extends WXSlider {
-    public static final String NEIGHBOR_SCALE = "neighborScale"; // the init scale of neighbor page
-    public static final String NEIGHBOR_ALPHA = "neighborAlpha"; // the init alpha of neighbor page
-    public static final String NEIGHBOR_SPACE = "neighborSpace"; // the init space of neighbor page
-    public static final String CURRENT_ITEM_SCALE = "currentItemScale"; // the scale of middle item
-
-    private static final int DEFAULT_NEIGHBOR_SPACE = 25;
-    private static final float DEFAULT_NEIGHBOR_SCALE = 0.8F;
-    private static final float DEFAULT_NEIGHBOR_ALPHA = 0.6F;
-    private static final float DEFAULT_CURRENT_ITEM_SCALE = 0.9F;
-
-    private float mNeighborScale = DEFAULT_NEIGHBOR_SCALE;
-    private float mNeighborAlpha = DEFAULT_NEIGHBOR_ALPHA;
-    private float mNeighborSpace = DEFAULT_NEIGHBOR_SPACE;
-    private float mCurrentItemScale = DEFAULT_CURRENT_ITEM_SCALE;
-
-    private ZoomTransformer mCachedTransformer;
-
-    public WXSliderNeighbor(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-        super(instance, parent, basicComponentData);
-    }
-
-    public static class Creator implements ComponentCreator {
-        public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-            return new WXSliderNeighbor(instance, parent, basicComponentData);
-        }
-    }
-
-    @Override
-    public void bindData(WXComponent component) {
-        super.bindData(component);
-    }
-
-    @Override
-    protected BaseFrameLayout initComponentHostView(@NonNull Context context) {
-        BaseFrameLayout view = new BaseFrameLayout(context);
-
-        // init view pager
-        FrameLayout.LayoutParams pagerParams = new FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
-        pagerParams.gravity = Gravity.CENTER;
-        mViewPager = new WXCircleViewPager(getContext());
-        mViewPager.setLayoutParams(pagerParams);
-
-        // init adapter
-        mAdapter = new WXCirclePageAdapter();
-        mViewPager.setAdapter(mAdapter);
-
-        // add to parent
-        view.addView(mViewPager);
-        mViewPager.addOnPageChangeListener(mPageChangeListener);
-
-        mViewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
-        registerActivityStateListener();
-
-        mViewPager.setPageTransformer(false, createTransformer());
-
-        return view;
-    }
-
-    ZoomTransformer createTransformer() {
-        if(mCachedTransformer == null) {
-            mCachedTransformer = new ZoomTransformer();
-        }
-        return mCachedTransformer;
-    }
-
-    @Override
-    public void addSubView(View view, final int index) {
-        if (view == null || mAdapter == null) {
-            return;
-        }
-
-        if (view instanceof WXCircleIndicator) {
-            return;
-        }
-
-        FrameLayout wrapper = new FrameLayout(getContext());
-        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-        params.gravity = Gravity.CENTER;
-        view.setLayoutParams(params);
-        wrapper.addView(view);
-        super.addSubView(wrapper,index);
-
-        updateAdapterScaleAndAlpha(mNeighborAlpha, mNeighborScale); // we need to set neighbor view status when added.
-
-        mViewPager.postDelayed(WXThread.secure(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    if(mViewPager.getRealCount() > 0 && index > 2) { // index > 2 mean more than two times, then need a fake drag
-                        // prevent a bug of init status. ZoomTransformer no called as excepted.
-                        mViewPager.beginFakeDrag();
-                        mViewPager.fakeDragBy(1); // must be 1
-                    }
-                }catch (IndexOutOfBoundsException e){
-                    // do nothing
-                } finally {
-                    try {
-                        mViewPager.endFakeDrag();
-                    }catch (Exception e) {
-                        // do nothing
-                    }
-                }
-            }
-        }), 50);
-    }
-
-    private void updateScaleAndAlpha(View view, float alpha, float scale) {
-        if(null == view) {
-            return;
-        }
-        if(alpha >= 0 && view.getAlpha() != alpha) {
-            view.setAlpha(alpha);
-        }
-        if(scale >= 0 && view.getScaleX() != scale) {
-            view.setScaleX(scale);
-            view.setScaleY(scale);
-        }
-    }
-
-    private void updateAdapterScaleAndAlpha(final float alpha, final float scale) {
-        final List<View> pageViews = mAdapter.getViews();
-        final int curPos = mViewPager.getCurrentItem();
-
-        if(pageViews.size() > 0) {
-            final View currentPage = pageViews.get(curPos);
-            updateScaleAndAlpha(((ViewGroup)currentPage).getChildAt(0), 1.0F, mCurrentItemScale);
-
-            if(pageViews.size() < 2) {
-                return;
-            }
-            //make sure View's width & height are measured.
-            currentPage.postDelayed(WXThread.secure(new Runnable() {
-                @Override
-                public void run() {
-                    //change left and right page's translation
-                    updateNeighbor(currentPage, alpha, scale);
-
-                }
-            }), 17);
-
-            // make sure only display view current, left, right.
-            int left = (curPos == 0) ? pageViews.size()-1 : curPos-1;
-            int right = (curPos == pageViews.size()-1) ? 0 : curPos+1;
-            for(int i =0; i<mAdapter.getRealCount(); i++) {
-                if(i != left && i != curPos && i != right) {
-                    ((ViewGroup)pageViews.get(i)).getChildAt(0).setAlpha(0F);
-                }
-            }
-        }
-    }
-
-    private void updateNeighbor(View currentPage, final float alpha, final float scale) {
-        final List<View> pageViews = mAdapter.getViews();
-        final int curPos = mViewPager.getCurrentItem();
-
-        float translation = calculateTranslation(currentPage);
-        int left = (curPos == 0) ? pageViews.size()-1 : curPos-1;
-        View leftPage = pageViews.get(left);
-        int right = (curPos == pageViews.size()-1) ? 0 : curPos+1;
-        View rightPage = pageViews.get(right);
-
-        if(pageViews.size() == 2) {
-            if(curPos == 0) {
-                moveRight(rightPage, translation, alpha, scale);
-            }else if(curPos == 1) {
-                moveLeft(leftPage, translation, alpha, scale);
-            }
-        } else {
-            moveLeft(leftPage, translation, alpha, scale);
-            moveRight(rightPage, translation, alpha, scale);
-        }
-    }
-
-    private void moveLeft(View page, float translation, float alpha, float scale) {
-        updateScaleAndAlpha(((ViewGroup)page).getChildAt(0), alpha, scale);
-        page.setTranslationX(translation);
-        ((ViewGroup)page).getChildAt(0).setTranslationX(translation);
-    }
-    private void moveRight(View page, float translation, float alpha, float scale) {
-        moveLeft(page, -translation, alpha, scale);
-    }
-
-    @WXComponentProp(name = NEIGHBOR_SCALE)
-    public void setNeighborScale(String input) {
-        float neighborScale = DEFAULT_NEIGHBOR_SCALE;
-        if (!TextUtils.isEmpty(input)) {
-            try {
-                neighborScale = Float.parseFloat(input);
-            } catch (NumberFormatException e) {
-            }
-        }
-
-        // addSubView is called before setProperty, so we need to modify the neighbor view in mAdapter.
-        if(this.mNeighborScale != neighborScale) {
-            this.mNeighborScale = neighborScale;
-            updateAdapterScaleAndAlpha(-1, neighborScale);
-        }
-    }
-
-    @WXComponentProp(name = NEIGHBOR_ALPHA)
-    public void setNeighborAlpha(String input) {
-        float neighborAlpha = DEFAULT_NEIGHBOR_ALPHA;
-        if (!TextUtils.isEmpty(input)) {
-            try {
-                neighborAlpha = Float.parseFloat(input);
-            } catch (NumberFormatException e) {
-            }
-        }
-
-        // The same work as setNeighborScale()
-        if(this.mNeighborAlpha != neighborAlpha) {
-            this.mNeighborAlpha = neighborAlpha;
-            updateAdapterScaleAndAlpha(neighborAlpha, -1);
-        }
-    }
-
-    @WXComponentProp(name = NEIGHBOR_SPACE)
-    @SuppressWarnings("unused")
-    public void setNeighborSpace(String input) {
-        float neighborSpace = DEFAULT_NEIGHBOR_SPACE;
-        if (!TextUtils.isEmpty(input)) {
-            try {
-                neighborSpace = Float.parseFloat(input);
-            } catch (NumberFormatException e) {
-            }
-        }
-
-        if(this.mNeighborSpace != neighborSpace) {
-            this.mNeighborSpace = neighborSpace;
-        }
-    }
-
-    @WXComponentProp(name = CURRENT_ITEM_SCALE)
-    @SuppressWarnings("unused")
-    public void setCurrentItemScale(String input) {
-        float currentItemScale = DEFAULT_CURRENT_ITEM_SCALE;
-        if (!TextUtils.isEmpty(input)) {
-            try {
-                currentItemScale = Float.parseFloat(input);
-            } catch (NumberFormatException e) {
-            }
-        }
-
-        if(this.mCurrentItemScale != currentItemScale) {
-            this.mCurrentItemScale = currentItemScale;
-            updateAdapterScaleAndAlpha(-1, -1);
-        }
-    }
-
-    @Override
-    protected boolean setProperty(String key, Object param) {
-        String input;
-        switch (key) {
-            case NEIGHBOR_SCALE:
-                input = WXUtils.getString(param, null);
-                if (input != null) {
-                    setNeighborScale(input);
-                }
-                return true;
-            case NEIGHBOR_ALPHA:
-                input = WXUtils.getString(param, null);
-                if (input != null) {
-                    setNeighborAlpha(input);
-                }
-                return true;
-            case NEIGHBOR_SPACE:
-                input = WXUtils.getString(param, null);
-                if (input != null) {
-                    setNeighborSpace(input);
-                }
-                return true;
-            case CURRENT_ITEM_SCALE:
-                input = WXUtils.getString(param, null);
-                if (input != null) {
-                    setCurrentItemScale(input);
-                }
-                return true;
-        }
-        return super.setProperty(key, param);
-    }
-
-    /**
-     * we need add translation for left and right card view.
-     * */
-    private float calculateTranslation(@NonNull View hostPage) {
-        if(!(hostPage instanceof ViewGroup)) {
-            return 0;
-        }
-        View realView = ((ViewGroup)hostPage).getChildAt(0);
-        float translation = (hostPage.getMeasuredWidth()-realView.getMeasuredWidth()*mNeighborScale)/4;
-        translation += ((hostPage.getMeasuredWidth()-realView.getMeasuredWidth() * mCurrentItemScale)/2 - WXViewUtils.getRealPxByWidth(mNeighborSpace, getInstance().getInstanceViewPortWidth()))/2 ;
-        return translation;
-    }
-
-    // Here is the trick.
-     class ZoomTransformer implements ViewPager.PageTransformer {
-        @Override
-        public void transformPage(View page, float position) {
-            int pagePosition = mAdapter.getPagePosition(page);
-            int curPosition = mViewPager.getCurrentItem();
-
-            int realCount = mAdapter.getRealCount();
-
-            boolean ignore = false;
-            if(curPosition != 0 && curPosition != realCount - 1 && Math.abs(pagePosition - curPosition) > 1)  {
-                ignore = true;
-            }
-            if(curPosition == 0 && pagePosition < realCount - 1 && pagePosition > 1) {
-                ignore = true;
-            }
-            if(curPosition == realCount - 1 && pagePosition < realCount - 2 && pagePosition > 0) {
-                ignore = true;
-            }
-            // just transfer the neighbor(left & right) page.
-            if(ignore) {
-                return;
-            }
-
-            View realView = ((ViewGroup)page).getChildAt(0);
-            if(realView == null){
-                return;
-            }
-            float alpha, scale;
-
-            if(position <= (-realCount + 1)) {
-                position = position + realCount;
-            }
-            if(position >= realCount - 1) {
-                position = position - realCount;
-            }
-
-            if (position >= -1 && position <= 1) {
-                float factor = Math.abs(Math.abs(position) - 1);
-                scale = mNeighborScale + factor * (mCurrentItemScale - mNeighborScale);
-                alpha = (1- mNeighborAlpha) * factor + mNeighborAlpha;
-
-                float translation = calculateTranslation(page);
-                if(position > 0){
-                    translation = (position*translation);
-                    realView.setTranslationX(-translation);
-                    page.setTranslationX(-translation);
-                }else if(position == 0){
-                    page.setTranslationX(0);
-                    realView.setTranslationX(0);
-                    updateAdapterScaleAndAlpha(mNeighborAlpha, mNeighborScale);
-                }else{
-                    if(realCount == 2 && Math.abs(position) == 1) {
-                        return;
-                    }
-                    translation = (-position*translation);
-                    realView.setTranslationX(translation);
-                    page.setTranslationX(translation);
-                }
-                realView.setScaleX(scale);
-                realView.setScaleY(scale);
-                realView.setAlpha(alpha);
-            }
-
-        }
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSwitch.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSwitch.java
deleted file mode 100644
index 714986e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSwitch.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.view.View;
-import android.widget.CompoundButton;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.layout.ContentBoxMeasurement;
-import com.taobao.weex.layout.MeasureSize;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXSwitchView;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@Component(lazyload = false)
-
-public class WXSwitch extends WXComponent<WXSwitchView> {
-
-  private CompoundButton.OnCheckedChangeListener mListener;
-
-  @Deprecated
-  public WXSwitch(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  public WXSwitch(final WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-    super(instance, parent, isLazy, basicComponentData);
-    setContentBoxMeasurement(new ContentBoxMeasurement() {
-      /** uiThread = false **/
-      @Override
-      public void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode) {
-        mMeasureWidth = 0;
-        mMeasureHeight = 0;
-        try {
-          WXSwitchView wxSwitchView = new WXSwitchView(instance.getContext());
-          int widthSpec, heightSpec;
-          heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
-          if (Float.isNaN(width)) {
-            widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
-          } else {
-            widthSpec = View.MeasureSpec.makeMeasureSpec((int) width, View.MeasureSpec.AT_MOST);
-          }
-
-          wxSwitchView.measure(widthSpec, heightSpec);
-          mMeasureWidth = wxSwitchView.getMeasuredWidth();
-          mMeasureHeight = wxSwitchView.getMeasuredHeight();
-        } catch (RuntimeException e) {
-          WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-      }
-
-      /** uiThread = false **/
-      @Override
-      public void layoutBefore() {
-      }
-
-      /** uiThread = false **/
-      @Override
-      public void layoutAfter(float computedWidth, float computedHeight) {
-      }
-    });
-  }
-
-  @Override
-  protected WXSwitchView initComponentHostView(@NonNull Context context) {
-    return new WXSwitchView(context);
-  }
-
-
-  @Override
-  public void addEvent(String type) {
-    super.addEvent(type);
-    if (type != null && type.equals(Constants.Event.CHANGE) && getHostView() != null) {
-      if (mListener == null) {
-        mListener = new CompoundButton.OnCheckedChangeListener() {
-          @Override
-          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-            Map<String, Object> params = new HashMap<>(2);
-            params.put("value", isChecked);
-
-            Map<String, Object> domChanges = new HashMap<>();
-            Map<String, Object> attrsChanges = new HashMap<>();
-            attrsChanges.put("checked",Boolean.toString(isChecked));
-            domChanges.put("attrs",attrsChanges);
-            fireEvent(Constants.Event.CHANGE, params,domChanges);
-          }
-        };
-      }
-      getHostView().setOnCheckedChangeListener(mListener);
-    }
-  }
-
-  @Override
-  protected void removeEventFromView(String type) {
-    super.removeEventFromView(type);
-    if (getHostView() != null && Constants.Event.CHANGE.equals(type)) {
-      getHostView().setOnCheckedChangeListener(null);
-    }
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.CHECKED:
-        Boolean result = WXUtils.getBoolean(param, null);
-        if (result != null) {
-          setChecked(result);
-        }
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @WXComponentProp(name = Constants.Name.CHECKED)
-  public void setChecked(boolean checked) {
-    getHostView().setOnCheckedChangeListener(null);
-    getHostView().setChecked(checked);
-    getHostView().setOnCheckedChangeListener(mListener);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java
deleted file mode 100644
index 1236e37..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.support.annotation.NonNull;
-import android.support.v4.content.LocalBroadcastManager;
-import android.text.Layout;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.layout.measurefunc.TextContentBoxMeasurement;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.flat.FlatComponent;
-import com.taobao.weex.ui.flat.widget.TextWidget;
-import com.taobao.weex.ui.view.WXTextView;
-import com.taobao.weex.utils.FontDO;
-import com.taobao.weex.utils.TypefaceUtil;
-import com.taobao.weex.utils.WXLogUtils;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Text component
- */
-@Component(lazyload = false)
-public class WXText extends WXComponent<WXTextView> implements FlatComponent<TextWidget> {
-
-  private TextWidget mTextWidget;
-
-  /**
-   * The default text size
-   **/
-  public static final int sDEFAULT_SIZE = 32;
-  private BroadcastReceiver mTypefaceObserver;
-  private String mFontFamily;
-
-  @Override
-  public boolean promoteToView(boolean checkAncestor) {
-    if (null != getInstance().getFlatUIContext()) {
-      return getInstance().getFlatUIContext().promoteToView(this, checkAncestor, WXText.class);
-    }
-    return false;
-  }
-
-  @Override
-  @NonNull
-  public TextWidget getOrCreateFlatWidget() {
-    if (mTextWidget == null) {
-      mTextWidget = new TextWidget(getInstance().getFlatUIContext());
-    }
-    return mTextWidget;
-  }
-
-  @Override
-  public boolean isVirtualComponent() {
-    return !promoteToView(true);
-  }
-
-  public static class Creator implements ComponentCreator {
-    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      return new WXText(instance, parent, basicComponentData);
-    }
-  }
-
-  @Deprecated
-  public WXText(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, basicComponentData);
-  }
-
-  public WXText(WXSDKInstance instance,
-                WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-    setContentBoxMeasurement(new TextContentBoxMeasurement(this));
-  }
-
-  @Override
-  protected WXTextView initComponentHostView(@NonNull Context context) {
-    WXTextView textView = new WXTextView(context);
-    textView.holdComponent(this);
-    return textView;
-  }
-
-  @Override
-  public void updateExtra(Object extra) {
-    super.updateExtra(extra);
-    if(extra instanceof Layout) {
-      final Layout layout = (Layout) extra;
-      if (!promoteToView(true)) {
-        getOrCreateFlatWidget().updateTextDrawable(layout);
-      } else if (getHostView() != null && !extra.equals(getHostView().getTextLayout())) {
-        getHostView().setTextLayout(layout);
-        getHostView().invalidate();
-      }
-    }
-  }
-
-  @Override
-  protected void setAriaLabel(String label) {
-    WXTextView text = getHostView();
-    if (text != null) {
-      text.setAriaLabel(label);
-    }
-  }
-
-  @Override
-  public void refreshData(WXComponent component) {
-    super.refreshData(component);
-    if (component instanceof WXText) {
-      updateExtra(component.getExtra());
-    }
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.LINES:
-      case Constants.Name.FONT_SIZE:
-      case Constants.Name.FONT_WEIGHT:
-      case Constants.Name.FONT_STYLE:
-      case Constants.Name.COLOR:
-      case Constants.Name.TEXT_DECORATION:
-      case Constants.Name.TEXT_ALIGN:
-      case Constants.Name.TEXT_OVERFLOW:
-      case Constants.Name.LINE_HEIGHT:
-      case Constants.Name.VALUE:
-        return true;
-      case Constants.Name.FONT_FAMILY:
-        if (param != null) {
-          registerTypefaceObserver(param.toString());
-        }
-        return true;
-      default:
-        return super.setProperty(key, param);
-    }
-  }
-
-  @Override
-  protected Object convertEmptyProperty(String propName, Object originalValue) {
-    switch (propName) {
-      case Constants.Name.FONT_SIZE:
-        return WXText.sDEFAULT_SIZE;
-      case Constants.Name.COLOR:
-        return "black";
-    }
-    return super.convertEmptyProperty(propName, originalValue);
-  }
-
-  @Override
-  protected void createViewImpl() {
-    if(promoteToView(true)) {
-      super.createViewImpl();
-    }
-  }
-
-  @Override
-  public void destroy() {
-    super.destroy();
-    if (WXEnvironment.getApplication() != null && mTypefaceObserver != null) {
-      WXLogUtils.d("WXText", "Unregister the typeface observer");
-      LocalBroadcastManager.getInstance(WXEnvironment.getApplication()).unregisterReceiver(mTypefaceObserver);
-      mTypefaceObserver = null;
-    }
-  }
-
-  private void registerTypefaceObserver(String desiredFontFamily) {
-    if (WXEnvironment.getApplication() == null) {
-      WXLogUtils.w("WXText", "ApplicationContent is null on register typeface observer");
-      return;
-    }
-    mFontFamily = desiredFontFamily;
-    if (mTypefaceObserver != null) {
-      return;
-    }
-
-    mTypefaceObserver = new BroadcastReceiver() {
-      @Override
-      public void onReceive(Context context, Intent intent) {
-        String fontFamily = intent.getStringExtra("fontFamily");
-        if (!mFontFamily.equals(fontFamily)) {
-          return;
-        }
-
-        FontDO fontDO = TypefaceUtil.getFontDO(fontFamily);
-        if (fontDO != null && fontDO.getTypeface() != null && getHostView() != null) {
-          WXTextView hostView = getHostView();
-          Layout layout = hostView.getTextLayout();
-          if (layout != null) {
-            layout.getPaint().setTypeface(fontDO.getTypeface());
-          } else {
-            WXLogUtils.d("WXText", "Layout not created");
-          }
-          WXBridgeManager
-              .getInstance().markDirty(getInstanceId(), getRef(), true);
-          forceRelayout();
-
-        }
-      }
-    };
-
-    LocalBroadcastManager.getInstance(WXEnvironment.getApplication()).registerReceiver(mTypefaceObserver, new IntentFilter(TypefaceUtil.ACTION_TYPE_FACE_AVAILABLE));
-  }
-
-
-  @Override
-  protected void layoutDirectionDidChanged(boolean isRTL) {
-    forceRelayout();
-  }
-
-  private void forceRelayout(){
-    WXBridgeManager.getInstance().post(new Runnable() {
-      @Override
-      public void run() {
-        if(contentBoxMeasurement instanceof TextContentBoxMeasurement){
-          ((TextContentBoxMeasurement) contentBoxMeasurement).forceRelayout();
-        }
-      }
-    });
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXTextDecoration.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXTextDecoration.java
deleted file mode 100644
index 44638ff..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXTextDecoration.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-public enum WXTextDecoration {
-  INVALID,
-  NONE,
-  UNDERLINE,
-  LINETHROUGH,
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
deleted file mode 100644
index 167eeb5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.content.Intent;
-import android.support.annotation.Nullable;
-import android.support.v4.view.ViewCompat;
-import android.util.Pair;
-import android.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXImageView;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.ArrayList;
-
-/**
- * All container components must implement this class
- */
-public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
-
-  private static final String TAG = "WXVContainer";
-  protected ArrayList<WXComponent> mChildren = new ArrayList<>();
-  private BoxShadowHost mBoxShadowHost;
-
-  @Deprecated
-  public WXVContainer(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  @Deprecated
-  public WXVContainer(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  public WXVContainer(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  /**
-   * Container will get focus before any of its descendants.
-   */
-  public void interceptFocus() {
-    T host = getHostView();
-    if (host != null) {
-      host.setFocusable(true);
-      host.setFocusableInTouchMode(true);
-      host.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-      host.requestFocus();
-    }
-  }
-
-  /**
-   * Container will can not receive focus
-   */
-  public void ignoreFocus() {
-    T host = getHostView();
-    if (host != null) {
-      host.setFocusable(false);
-      host.setFocusableInTouchMode(false);
-      host.clearFocus();
-    }
-  }
-
-  /**
-   * Offset top for children layout.
-   */
-  protected int getChildrenLayoutTopOffset() {
-    return 0;
-  }
-
-  /**
-   * use {@link #getHostView()} instead
-   */
-  @Deprecated
-  public ViewGroup getView() {
-    return getHostView();
-  }
-
-  @Override
-  public void applyLayoutAndEvent(WXComponent component) {
-    if (!isLazy()) {
-      if (component == null) {
-        component = this;
-      }
-      super.applyLayoutAndEvent(component);
-      int count = childCount();
-      for (int i = 0; i < count; i++) {
-        WXComponent child = getChild(i);
-        child.applyLayoutAndEvent(((WXVContainer) component).getChild(i));
-      }
-    }
-  }
-
-  /**
-   * Get or generate new layout parameter for child view
-   */
-  public ViewGroup.LayoutParams getChildLayoutParams(WXComponent child, View childView, int width, int height, int left, int right, int top, int bottom) {
-    ViewGroup.LayoutParams lp = null;
-    if (childView != null) {
-      lp = childView.getLayoutParams();
-    }
-
-    if(lp == null) {
-      lp = new ViewGroup.LayoutParams(width,height);
-    }else{
-      lp.width = width;
-      lp.height = height;
-      if(lp instanceof ViewGroup.MarginLayoutParams){
-        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, left, top, right, bottom);
-      }
-    }
-    return lp;
-  }
-
-
-  public Scrollable getFirstScroller() {
-    if (this instanceof Scrollable) {
-      return (Scrollable) this;
-    } else {
-      for (int i = 0; i < getChildCount(); i++) {
-        Scrollable scrollable = getChild(i).getFirstScroller();
-        if (scrollable != null) {
-          return scrollable;
-        }
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public void bindData(WXComponent component) {
-    if (!isLazy()) {
-      if (component == null) {
-        component = this;
-      }
-      super.bindData(component);
-      int count = childCount();
-      for (int i = 0; i < count; i++) {
-        getChild(i).bindData(((WXVContainer) component).getChild(i));
-      }
-    }
-  }
-
-  @Override
-  public void refreshData(WXComponent component) {
-    if (component == null) {
-      component = this;
-    }
-    super.refreshData(component);
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).refreshData(((WXVContainer) component).getChild(i));
-    }
-  }
-
-  /**
-   * return real View
-   */
-  @Override
-  public ViewGroup getRealView() {
-    return (ViewGroup) super.getRealView();
-  }
-
-  @Override
-  public void createViewImpl() {
-    super.createViewImpl();
-    int count = childCount();
-    for (int i = 0; i < count; ++i) {
-      createChildViewAt(i);
-    }
-    if (getHostView() != null) {
-      getHostView().setClipToPadding(false);
-    }
-  }
-
-  @Override
-  public void destroy() {
-    if (mChildren != null) {
-      int count = mChildren.size();
-      for (int i = 0; i < count; ++i) {
-        mChildren.get(i).destroy();
-      }
-      mChildren.clear();
-    }
-    super.destroy();
-  }
-
-  /**
-   * recycle component resources
-   */
-  public void recycled() {
-    if (mChildren != null && !isFixed() && getAttrs().canRecycled()) {
-      int count = mChildren.size();
-      for (int i = 0; i < count; ++i) {
-        mChildren.get(i).recycled();
-      }
-    }
-    super.recycled();
-
-  }
-
-  @Override
-  public View detachViewAndClearPreInfo() {
-    View original = super.detachViewAndClearPreInfo();
-    if (mChildren != null) {
-      int count = childCount();
-      for (int i = 0; i < count; ++i) {
-        mChildren.get(i).detachViewAndClearPreInfo();
-      }
-    }
-    return original;
-  }
-
-  public int childCount() {
-    return mChildren == null ? 0 : mChildren.size();
-  }
-
-  public WXComponent getChild(int index) {
-    if (mChildren == null || index < 0 || index >= mChildren.size()) {
-      //To avoid index out of bounds
-      return null;
-    }
-    return mChildren.get(index);
-  }
-
-  public int getChildCount() {
-    return childCount();
-  }
-
-  public void addChild(WXComponent child) {
-    addChild(child, -1);
-  }
-
-  public void addChild(WXComponent child, int index) {
-    if (child == null || index < -1) {
-      return;
-    }
-    child.mDeepInComponentTree = this.mDeepInComponentTree +1;
-    getInstance().setMaxDomDeep(child.mDeepInComponentTree);
-    int count = mChildren.size();
-    index = index >= count ? -1 : index;
-    if (index == -1) {
-      mChildren.add(child);
-    } else {
-      mChildren.add(index, child);
-    }
-  }
-
-  public final int indexOf(WXComponent comp) {
-    return mChildren.indexOf(comp);
-  }
-
-  public void createChildViewAt(int index) {
-    Pair<WXComponent, Integer> ret = rearrangeIndexAndGetChild(index);
-    if (ret.first != null) {
-      WXComponent child = ret.first;
-      child.createView();
-      if (!child.isVirtualComponent()) {
-        addSubView(child.getHostView(), ret.second);
-      }
-    }
-  }
-
-  protected Pair<WXComponent, Integer> rearrangeIndexAndGetChild(int index) {
-    int indexToCreate = index;
-    if (indexToCreate < 0) {
-      indexToCreate = childCount() - 1;
-    }
-
-    if (indexToCreate < 0) {
-      return new Pair<>(null, indexToCreate);
-    } else {
-      return new Pair<>(getChild(indexToCreate), indexToCreate);
-    }
-  }
-
-  public void addSubView(View child, int index) {
-    if (child == null || getRealView() == null) {
-      return;
-    }
-
-    int count = getRealView().getChildCount();
-    index = index >= count ? -1 : index;
-    if (index == -1) {
-      getRealView().addView(child);
-    } else {
-      getRealView().addView(child, index);
-    }
-    WXSDKInstance instance = getInstance();
-    if (null != instance){
-      instance.getApmForInstance().hasAddView = true;
-    }
-  }
-
-  public void remove(WXComponent child, boolean destroy) {
-    if (child == null || mChildren == null || mChildren.size() == 0) {
-      return;
-    }
-
-    mChildren.remove(child);
-    if (getInstance() != null
-            && getInstance().getRootView() != null
-            && child.isFixed()) {
-      getInstance().removeFixedView(child.getHostView());
-    } else if (getRealView() != null) {
-      if (!child.isVirtualComponent()) {
-        ViewParent parent = null;
-        if(child.getParent() instanceof  WXScroller){
-          if(child.getHostView() != null){
-            parent = child.getHostView().getParent();
-          }
-        }
-        if(parent != null && parent instanceof  ViewGroup){
-          ((ViewGroup) parent).removeView(child.getHostView());
-        }else{
-          getRealView().removeView(child.getHostView());
-        }
-      } else {
-        child.removeVirtualComponent();
-      }
-    }
-    if (destroy) {
-      child.destroy();
-    }
-  }
-
-  @Override
-  public void notifyAppearStateChange(String wxEventType, String direction) {
-    super.notifyAppearStateChange(wxEventType, direction);
-    if (getHostView() == null || mChildren == null) {
-      return;
-    }
-    for (WXComponent component : mChildren) {
-      if (component.getHostView() != null && !(component.getHostView().getVisibility() == View.VISIBLE)) {
-        wxEventType = Constants.Event.DISAPPEAR;
-      }
-      component.notifyAppearStateChange(wxEventType, direction);
-    }
-  }
-
-  /********************************************************
-   *  begin hook Activity life cycle callback             *
-   ********************************************************/
-  @Override
-  public void onActivityCreate() {
-    super.onActivityCreate();
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityCreate();
-    }
-  }
-
-  @Override
-  public void onActivityStart() {
-    super.onActivityStart();
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityStart();
-    }
-
-  }
-
-  @Override
-  public void onActivityPause() {
-    super.onActivityPause();
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityPause();
-    }
-  }
-
-  @Override
-  public void onActivityResume() {
-    super.onActivityResume();
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityResume();
-    }
-  }
-
-  @Override
-  public void onActivityStop() {
-    super.onActivityStop();
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityStop();
-    }
-  }
-
-  @Override
-  public void onActivityDestroy() {
-    super.onActivityDestroy();
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityDestroy();
-    }
-
-  }
-
-  @Override
-  public boolean onActivityBack() {
-    super.onActivityBack();
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityBack();
-    }
-    return false;
-  }
-
-  @Override
-  public void onActivityResult(int requestCode, int resultCode, Intent data) {
-    super.onActivityResult(requestCode, resultCode, data);
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onActivityResult(requestCode, resultCode, data);
-    }
-
-  }
-
-  public boolean onCreateOptionsMenu(Menu menu) {
-    super.onCreateOptionsMenu(menu);
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onCreateOptionsMenu(menu);
-    }
-    return false;
-  }
-
-
-  @Override
-  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
-    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-
-    int count = childCount();
-    for (int i = 0; i < count; i++) {
-      getChild(i).onRequestPermissionsResult(requestCode, permissions, grantResults);
-    }
-  }
-
-  @Override
-  public void onRenderFinish(@RenderState int state) {
-    for (int i = 0; i < getChildCount(); i++) {
-      WXComponent child = getChild(i);
-      child.mTraceInfo.uiQueueTime = mTraceInfo.uiQueueTime;
-      child.onRenderFinish(state);
-    }
-    super.onRenderFinish(state);
-  }
-
-  @JSMethod
-  public void releaseImageList(String viewTreeRecycle){
-    if(getHostView() == null
-            || !ViewCompat.isAttachedToWindow(getHostView())
-            || !(getHostView() instanceof  ViewGroup)){
-      return;
-    }
-    boolean isViewTree = WXUtils.getBoolean(viewTreeRecycle, false);
-    if(isViewTree){
-      doViewTreeRecycleImageView(getHostView(), true);
-    }else{
-      int count = getChildCount();
-      for(int i=0; i<count; i++){
-        WXComponent component =  getChild(i);
-        if(component instanceof  WXImage && ((WXImage) component).getHostView() instanceof WXImageView){
-          WXImageView imageView = (WXImageView) component.getHostView();
-          if(imageView != null && ViewCompat.isAttachedToWindow(imageView)){
-            imageView.autoReleaseImage();
-          }
-        }else if(component instanceof  WXVContainer){
-          ((WXVContainer) component).releaseImageList(viewTreeRecycle);
-        }
-      }
-    }
-  }
-
-  @JSMethod
-  public void recoverImageList(String viewTreeRecycle){
-    if(getHostView() == null
-            || !ViewCompat.isAttachedToWindow(getHostView())
-            || !(getHostView() instanceof  ViewGroup)){
-      return;
-    }
-    boolean isViewTree = WXUtils.getBoolean(viewTreeRecycle, false);
-    if(isViewTree){
-      doViewTreeRecycleImageView(getHostView(), false);
-    }else{
-      int count = getChildCount();
-      for(int i=0; i<count; i++){
-        WXComponent component =  getChild(i);
-        if(component instanceof  WXImage && ((WXImage) component).getHostView() instanceof WXImageView){
-          WXImageView imageView = (WXImageView) component.getHostView();
-          if(imageView != null && ViewCompat.isAttachedToWindow(imageView)){
-            imageView.autoRecoverImage();
-          }
-        }else if(component instanceof  WXVContainer){
-          ((WXVContainer) component).recoverImageList(viewTreeRecycle);
-        }
-      }
-    }
-  }
-
-  /**
-   * transverse view tree, and recycle wximageview in container
-   * */
-  private void doViewTreeRecycleImageView(ViewGroup viewGroup, boolean isRelease){
-    int count = viewGroup.getChildCount();
-    for(int i=0; i<count; i++){
-      View view = viewGroup.getChildAt(i);
-      if(view instanceof  WXImageView){
-        if(isRelease){
-          ((WXImageView) view).autoReleaseImage();
-        }else{
-          ((WXImageView) view).autoRecoverImage();
-        }
-      }else if(view instanceof  ViewGroup){
-        doViewTreeRecycleImageView((ViewGroup) view, isRelease);
-      }
-    }
-  }
-
-
-  public void requestDisallowInterceptTouchEvent(boolean requestDisallowInterceptTouchEvent) {
-    if(mGesture != null){
-      if(mGesture.isRequestDisallowInterceptTouchEvent()){
-        return;
-      }
-      mGesture.setRequestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
-    }
-    if(getParent() != null){
-      getParent().requestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
-    }
-  }
-
-  /********************************
-   *  end hook Activity life cycle callback
-   ********************************************************/
-
-  public @Nullable
-  View getBoxShadowHost(boolean isClear) {
-    if (isClear) {
-      // Return existed host if want clear shadow
-      return mBoxShadowHost;
-    }
-
-    ViewGroup hostView = getHostView();
-    if (hostView == null) {
-      return null;
-    }
-
-    try {
-      String type = getComponentType();
-      if (WXBasicComponentType.DIV.equals(type)) {
-        WXLogUtils.d("BoxShadow", "Draw box-shadow with BoxShadowHost on div: " + toString());
-        if (mBoxShadowHost == null) {
-          mBoxShadowHost = new BoxShadowHost(getContext());
-          WXViewUtils.setBackGround(mBoxShadowHost, null, this);
-
-          hostView.addView(mBoxShadowHost);
-        }
-
-        CSSShorthand padding = this.getPadding();
-        CSSShorthand border = this.getBorder();
-
-        int left = (int) (padding.get(CSSShorthand.EDGE.LEFT) + border.get(CSSShorthand.EDGE.LEFT));
-        int top = (int) (padding.get(CSSShorthand.EDGE.TOP) + border.get(CSSShorthand.EDGE.TOP));
-        int right = (int) (padding.get(CSSShorthand.EDGE.RIGHT) + border.get(CSSShorthand.EDGE.RIGHT));
-        int bottom = (int) (padding.get(CSSShorthand.EDGE.BOTTOM) + border.get(CSSShorthand.EDGE.BOTTOM));
-
-        ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(hostView.getLayoutParams()) ;
-        this.setMarginsSupportRTL(layoutParams, -left, -top, -right, -bottom);
-
-        mBoxShadowHost.setLayoutParams(layoutParams);
-        
-        hostView.removeView(mBoxShadowHost);
-        hostView.addView(mBoxShadowHost);
-        return mBoxShadowHost;
-      }
-    } catch (Throwable t) {
-      WXLogUtils.w("BoxShadow", t);
-    }
-    return hostView;
-  }
-
-  private class BoxShadowHost extends View {
-    public BoxShadowHost(Context context) {
-      super(context);
-    }
-  }
-
-  public void appendTreeCreateFinish() {
-    
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVideo.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVideo.java
deleted file mode 100644
index 0851825..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVideo.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.WXVideoView;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-@Component(lazyload = false)
-
-public class WXVideo extends WXComponent<FrameLayout> {
-
-  private boolean mAutoPlay;
-  private WXVideoView.Wrapper mWrapper;
-
-  /**
-   * package
-   **/
-  boolean mPrepared;
-  private boolean mError;
-
-  @Deprecated
-  public WXVideo(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-  public WXVideo(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-    super(instance, parent, isLazy, basicComponentData);
-  }
-
-  @Override
-  protected FrameLayout initComponentHostView(@NonNull Context context) {
-    final WXVideoView.Wrapper video = new WXVideoView.Wrapper(context);
-    video.setOnErrorListener(new MediaPlayer.OnErrorListener() {
-
-      @Override
-      public boolean onError(MediaPlayer mp, int what, int extra) {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d("Video", "onError:" + what);
-        }
-        video.getProgressBar().setVisibility(View.GONE);
-        mPrepared = false;
-        mError = true;
-
-        if (getEvents().contains(Constants.Event.FAIL)) {
-          WXVideo.this.notify(Constants.Event.FAIL, Constants.Value.STOP);
-        }
-        return true;
-      }
-    });
-
-    video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
-
-      @Override
-      public void onPrepared(MediaPlayer mediaPlayer) {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d("Video", "onPrepared");
-        }
-        video.getProgressBar().setVisibility(View.GONE);
-        mPrepared = true;
-        if (mAutoPlay) {
-          video.start();
-        }
-
-        //callback from video view, so videoview should not null
-        WXVideoView videoView = video.getVideoView();
-        videoView.seekTo(5);
-
-        if (video.getMediaController() != null) {
-          if (!mStopped) {
-            video.getMediaController().show(3);
-          } else {
-            video.getMediaController().hide();
-          }
-        }
-
-        mStopped = false;
-      }
-    });
-
-    video.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
-
-      @Override
-      public void onCompletion(MediaPlayer mediaPlayer) {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d("Video", "onCompletion");
-        }
-        if (getEvents().contains(Constants.Event.FINISH)) {
-          WXVideo.this.notify(Constants.Event.FINISH, Constants.Value.STOP);
-        }
-      }
-    });
-
-    video.setOnVideoPauseListener(new WXVideoView.VideoPlayListener() {
-
-      @Override
-      public void onPause() {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d("Video", "onPause");
-        }
-        if (getEvents().contains(Constants.Event.PAUSE)) {
-          WXVideo.this.notify(Constants.Event.PAUSE, Constants.Value.PAUSE);
-        }
-      }
-
-      @Override
-      public void onStart() {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d("Video", "onStart");
-        }
-
-        if (getEvents().contains(Constants.Event.START)) {
-          WXVideo.this.notify(Constants.Event.START, Constants.Value.PLAY);
-        }
-      }
-    });
-    mWrapper = video;
-    return video;
-  }
-
-  private void notify(String event, String newStatus) {
-    Map<String, Object> params = new HashMap<>(2);
-    params.put(Constants.Name.PLAY_STATUS, newStatus);
-    params.put("timeStamp", System.currentTimeMillis());
-
-    Map<String, Object> domChanges = new HashMap<>();
-    Map<String, Object> attrsChanges = new HashMap<>();
-    attrsChanges.put(Constants.Name.PLAY_STATUS, newStatus);
-    domChanges.put("attrs", attrsChanges);
-
-    WXSDKManager.getInstance().fireEvent(getInstanceId(), getRef(), event, params, domChanges);
-  }
-
-  @Override
-  public void bindData(WXComponent component) {
-    super.bindData(component);
-    addEvent(Constants.Event.APPEAR);
-  }
-
-  @Override
-  public void notifyAppearStateChange(String wxEventType, String direction) {
-    super.notifyAppearStateChange(wxEventType, direction);
-    mWrapper.createVideoViewIfVisible();
-  }
-
-  @Override
-  public void destroy() {
-    super.destroy();
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case Constants.Name.SRC:
-        String src = WXUtils.getString(param, null);
-        if (src != null) {
-          setSrc(src);
-        }
-        return true;
-      case Constants.Name.AUTO_PLAY:
-      case Constants.Name.AUTOPLAY:
-        Boolean result = WXUtils.getBoolean(param, null);
-        if (result != null) {
-          setAutoPlay(result);
-        }
-        return true;
-      case Constants.Name.ZORDERTOP:
-        Boolean zOrderTop = WXUtils.getBoolean(param, null);
-        if (zOrderTop != null) {
-            mWrapper.getVideoView().setZOrderOnTop(zOrderTop);
-        }
-        return true;
-      case Constants.Name.PLAY_STATUS:
-        String status = WXUtils.getString(param, null);
-        if (status != null) {
-          setPlaystatus(status);
-        }
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @WXComponentProp(name = Constants.Name.SRC)
-  public void setSrc(String src) {
-    if (TextUtils.isEmpty(src) || getHostView() == null) {
-      return;
-    }
-
-    if (!TextUtils.isEmpty(src)) {
-      WXSDKInstance instance = getInstance();
-      mWrapper.setVideoURI(instance.rewriteUri(Uri.parse(src), URIAdapter.VIDEO));
-      mWrapper.getProgressBar().setVisibility(View.VISIBLE);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.AUTO_PLAY)
-  public void setAutoPlay(boolean autoPlay) {
-    mAutoPlay = autoPlay;
-    if(autoPlay){
-      mWrapper.createIfNotExist();
-      mWrapper.start();
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.CONTROLS)
-  public void setControls(String controls) {
-    if (TextUtils.equals("controls", controls)) {
-      mWrapper.setControls(true);
-    } else if (TextUtils.equals("nocontrols", controls)) {
-      mWrapper.setControls(false);
-    }
-  }
-
-  private boolean mStopped;
-
-  @WXComponentProp(name = Constants.Name.PLAY_STATUS)
-  public void setPlaystatus(String playstatus) {
-
-    if (mPrepared && !mError && !mStopped) {
-      if (playstatus.equals(Constants.Value.PLAY)) {
-        mWrapper.start();
-      } else if (playstatus.equals(Constants.Value.PAUSE)) {
-        mWrapper.pause();
-      } else if (playstatus.equals(Constants.Value.STOP)) {
-        mWrapper.stopPlayback();
-        mStopped = true;
-      }
-    } else if ((mError || mStopped) && playstatus.equals(Constants.Value.PLAY)) {
-      mError = false;
-      mWrapper.resume();
-
-      mWrapper.getProgressBar().setVisibility(View.VISIBLE);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java
deleted file mode 100644
index a536c46..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXWeb.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.content.Context;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.view.View;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.view.IWebView;
-import com.taobao.weex.ui.view.WXWebView;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-@Component(lazyload = false)
-
-public class WXWeb extends WXComponent {
-
-    public static final String GO_BACK = "goBack";
-    public static final String GO_FORWARD = "goForward";
-    public static final String RELOAD = "reload";
-    public static final String POST_MESSAGE = "postMessage";
-    protected IWebView mWebView;
-
-    @Deprecated
-    public WXWeb(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-        this(instance, parent, isLazy, basicComponentData);
-    }
-
-    public WXWeb(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-        super(instance, parent, isLazy, basicComponentData);
-        createWebView();
-    }
-
-    protected void createWebView(){
-        String origin = null;
-        try {
-            String bundleUrl = WXSDKManager.getInstance().getSDKInstance(getInstanceId()).getBundleUrl();
-            Uri uri = Uri.parse(bundleUrl);
-            String scheme = uri.getScheme();
-            String authority = uri.getAuthority();
-            if (!TextUtils.isEmpty(scheme) && !TextUtils.isEmpty(authority)) {
-                origin = scheme + "://" + authority;
-            }
-        } catch (Exception e) {
-            // do noting
-        }
-        mWebView = new WXWebView(getContext(), origin);
-    }
-
-    @Override
-    protected View initComponentHostView(@NonNull Context context) {
-        mWebView.setOnErrorListener(new IWebView.OnErrorListener() {
-            @Override
-            public void onError(String type, Object message) {
-                fireEvent(type, message);
-            }
-        });
-        mWebView.setOnPageListener(new IWebView.OnPageListener() {
-            @Override
-            public void onReceivedTitle(String title) {
-                if (getEvents().contains(Constants.Event.RECEIVEDTITLE)) {
-                    Map<String, Object> params = new HashMap<>();
-                    params.put("title", title);
-                    fireEvent(Constants.Event.RECEIVEDTITLE, params);
-                }
-            }
-
-            @Override
-            public void onPageStart(String url) {
-                if (getEvents().contains(Constants.Event.PAGESTART)) {
-                    Map<String, Object> params = new HashMap<>();
-                    params.put("url", url);
-                    fireEvent(Constants.Event.PAGESTART, params);
-                }
-            }
-
-            @Override
-            public void onPageFinish(String url, boolean canGoBack, boolean canGoForward) {
-                if (getEvents().contains(Constants.Event.PAGEFINISH)) {
-                    Map<String, Object> params = new HashMap<>();
-                    params.put("url", url);
-                    params.put("canGoBack", canGoBack);
-                    params.put("canGoForward", canGoForward);
-                    fireEvent(Constants.Event.PAGEFINISH, params);
-                }
-            }
-        });
-        mWebView.setOnMessageListener(new IWebView.OnMessageListener() {
-            @Override
-            public void onMessage(Map<String, Object> params) {
-                fireEvent(Constants.Event.ONMESSAGE, params);
-            }
-        });
-        return mWebView.getView();
-    }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-        getWebView().destroy();
-    }
-
-    @Override
-    protected boolean setProperty(String key, Object param) {
-        switch (key) {
-            case Constants.Name.SHOW_LOADING:
-                Boolean result = WXUtils.getBoolean(param,null);
-                if (result != null)
-                    setShowLoading(result);
-                return true;
-            case Constants.Name.SRC:
-                String src = WXUtils.getString(param,null);
-                if (src != null)
-                    setUrl(src);
-                return true;
-            case Constants.Name.SOURCE:
-                String source = WXUtils.getString(param,null);
-                if (source != null)
-                    setSource(source);
-                return true;
-        }
-        return super.setProperty(key,param);
-    }
-
-    @WXComponentProp(name = Constants.Name.SHOW_LOADING)
-    public void setShowLoading(boolean showLoading) {
-        getWebView().setShowLoading(showLoading);
-    }
-
-    @WXComponentProp(name = Constants.Name.SRC)
-    public void setUrl(String url) {
-        if (TextUtils.isEmpty(url) || getHostView() == null) {
-            return;
-        }
-        if (!TextUtils.isEmpty(url)) {
-            loadUrl(getInstance().rewriteUri(Uri.parse(url), URIAdapter.WEB).toString());
-        }
-    }
-
-    @WXComponentProp(name = Constants.Name.SOURCE)
-    public void setSource(String source) {
-        if (!TextUtils.isEmpty(source) && getHostView() != null) {
-            loadDataWithBaseURL(source);
-        }
-    }
-
-    public void setAction(String action, Object data) {
-        if (!TextUtils.isEmpty(action)) {
-            if (action.equals(GO_BACK)) {
-                goBack();
-            } else if (action.equals(GO_FORWARD)) {
-                goForward();
-            } else if (action.equals(RELOAD)) {
-                reload();
-            } else if (action.equals(POST_MESSAGE)) {
-                postMessage(data);
-            }
-        }
-    }
-
-    private void fireEvent(String type, Object message) {
-        if (getEvents().contains(Constants.Event.ERROR)) {
-            Map<String, Object> params = new HashMap<>();
-            params.put("type", type);
-            params.put("errorMsg", message);
-            fireEvent(Constants.Event.ERROR, params);
-        }
-    }
-
-    private void loadUrl(String url) {
-        getWebView().loadUrl(url);
-    }
-
-    private void loadDataWithBaseURL(String source) {
-        getWebView().loadDataWithBaseURL(source);
-    }
-
-    @JSMethod
-    public void reload() {
-        getWebView().reload();
-    }
-
-    @JSMethod
-    public void goForward() {
-        getWebView().goForward();
-    }
-
-    @JSMethod
-    public void goBack() {
-        getWebView().goBack();
-    }
-
-    @JSMethod
-    public void postMessage(Object msg) {
-        getWebView().postMessage(msg);
-    }
-
-    private IWebView getWebView() {
-        return mWebView;
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/basic/WXBasicComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/basic/WXBasicComponent.java
deleted file mode 100644
index 4164475..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/basic/WXBasicComponent.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.basic;
-
-import android.support.annotation.NonNull;
-import android.view.View;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.action.GraphicPosition;
-import com.taobao.weex.ui.action.GraphicSize;
-import com.taobao.weex.ui.component.WXBasicComponentType;
-import com.taobao.weex.ui.component.WXComponent;
-import java.util.Map;
-import java.util.Set;
-
-public abstract class WXBasicComponent<T extends View> {
-
-  private Object mExtra;
-  private String mComponentType;
-  private String mRef;
-  private GraphicPosition mLayoutPosition;
-  private GraphicSize mLayoutSize;
-  private boolean mIsLayoutRTL;
-  private BasicComponentData mBasicComponentData;
-
-  private int mViewPortWidth = 750;
-
-  public WXBasicComponent(BasicComponentData basicComponentData) {
-    this.mBasicComponentData = basicComponentData;
-    this.mRef = basicComponentData.mRef;
-    this.mComponentType = basicComponentData.mComponentType;
-  }
-
-  public BasicComponentData getBasicComponentData() {
-    return mBasicComponentData;
-  }
-
-  protected void bindComponent(WXComponent component) {
-    mComponentType = component.getComponentType();
-    mRef = component.getRef();
-  }
-
-  public final @NonNull
-  WXStyle getStyles() {
-    return mBasicComponentData.getStyles();
-  }
-
-  public final @NonNull
-  WXAttr getAttrs() {
-    return mBasicComponentData.getAttrs();
-  }
-
-  public final @NonNull
-  WXEvent getEvents() {
-    return mBasicComponentData.getEvents();
-  }
-
-  /**
-   * Get this node's margin, as defined by cssstyle + default margin.
-   */
-  public final @NonNull
-  CSSShorthand getMargin() {
-    return mBasicComponentData.getMargin();
-  }
-
-  /**
-   * Get this node's padding, as defined by cssstyle + default padding.
-   */
-  public final @NonNull
-  CSSShorthand getPadding() {
-    return mBasicComponentData.getPadding();
-  }
-
-  /**
-   * Get this node's border, as defined by cssstyle.
-   */
-  public @NonNull
-  CSSShorthand getBorder() {
-    return mBasicComponentData.getBorder();
-  }
-
-  public final void setMargins(@NonNull CSSShorthand margins) {
-    mBasicComponentData.setMargins(margins);
-  }
-
-  public final void setPaddings(@NonNull CSSShorthand paddings) {
-    mBasicComponentData.setPaddings(paddings);
-  }
-
-  public final void setBorders(@NonNull CSSShorthand borders) {
-    mBasicComponentData.setBorders(borders);
-  }
-
-  public final void addAttr(Map<String, Object> attrs) {
-    if (attrs == null || attrs.isEmpty()) {
-      return;
-    }
-    mBasicComponentData.addAttr(attrs);
-  }
-
-  public final void addStyle(Map<String, Object> styles) {
-    if (styles == null || styles.isEmpty()) {
-      return;
-    }
-    mBasicComponentData.addStyle(styles);
-  }
-
-  public final void addStyle(Map<String, Object> styles, boolean byPesudo) {
-    if (styles == null || styles.isEmpty()) {
-      return;
-    }
-    mBasicComponentData.addStyle(styles, byPesudo);
-  }
-
-  public final void updateStyle(Map<String, Object> styles, boolean byPesudo){
-    if (styles == null || styles.isEmpty()) {
-      return;
-    }
-    mBasicComponentData.getStyles().updateStyle(styles, byPesudo);
-  }
-
-  public final void addEvent(Set<String> events) {
-    if (events == null || events.isEmpty()) {
-      return;
-    }
-
-    mBasicComponentData.addEvent(events);
-  }
-
-  public final void addShorthand(Map<String, String> shorthand) {
-    if (!shorthand.isEmpty() && mBasicComponentData != null) {
-      mBasicComponentData.addShorthand(shorthand);
-    }
-  }
-
-  public int getViewPortWidth() {
-    return mViewPortWidth;
-  }
-
-  public void setViewPortWidth(int mViewPortWidth) {
-    this.mViewPortWidth = mViewPortWidth;
-  }
-
-  public Object getExtra() {
-    return mExtra;
-  }
-
-  public void updateExtra(Object extra) {
-    this.mExtra = extra;
-  }
-
-  public String getComponentType() {
-    return mComponentType;
-  }
-
-  public String getRef() {
-    return mRef;
-  }
-
-  public void setIsLayoutRTL(boolean isRTL) {
-    mIsLayoutRTL = isRTL;
-  }
-
-  public boolean isLayoutRTL() {
-    return mIsLayoutRTL;
-  }
-
-  public GraphicPosition getLayoutPosition() {
-    if (mLayoutPosition == null) {
-      mLayoutPosition = new GraphicPosition(0, 0, 0, 0);
-    }
-    return mLayoutPosition;
-  }
-
-  protected void setLayoutPosition(GraphicPosition mLayoutPosition) {
-    this.mLayoutPosition = mLayoutPosition;
-  }
-
-  public GraphicSize getLayoutSize() {
-    if (mLayoutSize == null) {
-      mLayoutSize = new GraphicSize(0, 0);
-    }
-    return mLayoutSize;
-  }
-
-  protected void setLayoutSize(GraphicSize mLayoutSize) {
-    this.mLayoutSize = mLayoutSize;
-  }
-
-  public float getCSSLayoutTop() {
-    return mLayoutPosition == null ? 0 : mLayoutPosition.getTop();
-  }
-
-  public float getCSSLayoutBottom() {
-    return mLayoutPosition == null ? 0 : mLayoutPosition.getBottom();
-  }
-
-  public float getCSSLayoutLeft() {
-    return mLayoutPosition == null ? 0 : mLayoutPosition.getLeft();
-  }
-
-  public float getCSSLayoutRight() {
-    return mLayoutPosition == null ? 0 : mLayoutPosition.getRight();
-  }
-
-  public float getLayoutWidth() {
-    return mLayoutSize == null ? 0 : mLayoutSize.getWidth();
-  }
-
-  public float getLayoutHeight() {
-    return mLayoutSize == null ? 0 : mLayoutSize.getHeight();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/AsynLayoutTask.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/AsynLayoutTask.java
deleted file mode 100644
index 564c058..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/AsynLayoutTask.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.binding;
-
-import android.os.AsyncTask;
-
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.list.template.TemplateDom;
-import com.taobao.weex.ui.component.list.template.TemplateViewHolder;
-
-/**
- * Created by furture on 2018/5/11.
- */
-
-class AsynLayoutTask extends AsyncTask<Void, Void, Void> {
-
-    private final TemplateViewHolder templateViewHolder;
-    private final int position;
-    private final WXComponent component;
-
-    AsynLayoutTask(TemplateViewHolder templateViewHolder, int position, WXComponent component) {
-        this.templateViewHolder = templateViewHolder;
-        this.position = position;
-        this.component = component;
-    }
-
-    @Override
-    protected Void doInBackground(Void... params) {
-        if(templateViewHolder.getHolderPosition() == position){
-            if(component.getInstance() != null && !component.getInstance().isDestroy()) {
-                synchronized (templateViewHolder.getTemplateList()){
-                    if(templateViewHolder.getTemplateList().isDestoryed()){
-                        return null;
-                    }
-                    Layouts.doLayoutOnly(component, templateViewHolder);
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    protected void onPostExecute(Void aVoid) {
-        if(position == templateViewHolder.getHolderPosition()) {
-            if(component.getInstance() != null && !component.getInstance().isDestroy()) {
-                Layouts.setLayout(component, false);
-                if(templateViewHolder.getHolderPosition() >= 0){
-                    templateViewHolder.getTemplateList().fireEvent("_attach_slot", TemplateDom.findAllComponentRefs(templateViewHolder.getTemplateList().getRef(), position, component));
-                }
-            }
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java
deleted file mode 100644
index 9320bce..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.binding;
-
-
-
-import android.os.AsyncTask;
-import android.util.Log;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.component.list.template.TemplateDom;
-import com.taobao.weex.ui.component.list.template.TemplateViewHolder;
-import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
-import com.taobao.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-/**
- * Created by furture on 2017/8/21.
- */
-public class Layouts {
-    /**
-     * do dom layout async or sync , and set layout to component on main.
-     * on first use do sync layout, when compontnet reuse do async layout
-     * */
-    public static void doLayoutAsync(final TemplateViewHolder templateViewHolder, boolean async){
-        final WXComponent component = templateViewHolder.getComponent();
-        final  int position = templateViewHolder.getHolderPosition();
-        if(templateViewHolder.asyncTask != null){
-            templateViewHolder.asyncTask.cancel(false);
-            templateViewHolder.asyncTask = null;
-        }
-        if(async){
-            AsyncTask<Void, Void, Void> asyncTask = new AsynLayoutTask(templateViewHolder, position, component);
-            templateViewHolder.asyncTask = asyncTask;
-            asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); //serial executor is better
-        }else{
-            doLayoutOnly(component, templateViewHolder);
-            setLayout(component, false);
-            if(templateViewHolder.getHolderPosition() >= 0){
-                templateViewHolder.getTemplateList().fireEvent("_attach_slot", TemplateDom.findAllComponentRefs(templateViewHolder.getTemplateList().getRef(), position, component));
-            }
-        }
-
-    }
-    /**
-     * @param layoutHeight height
-     * @param layoutWidth width
-     * */
-    public static void doLayoutSync(WXCell component, float layoutWidth, float layoutHeight){
-        doSafeLayout(component, layoutWidth, layoutHeight);
-        setLayout(component, false);
-    }
-
-        /**
-         * safe layout
-         * */
-    public static void doLayoutOnly(WXComponent component, TemplateViewHolder holder){
-        doSafeLayout(component, holder.getTemplateList().getLayoutWidth(), holder.getTemplateList().getLayoutHeight());
-    }
-
-    private static void doSafeLayout(WXComponent component, float layoutWidth, float layoutHeight){
-        try{
-            long start = System.currentTimeMillis();
-            int height = NativeRenderObjectUtils.nativeLayoutRenderObject(component.getRenderObjectPtr(),
-                    layoutWidth,
-                    layoutHeight);
-            if(WXEnvironment.isOpenDebugLog() && WXRecyclerTemplateList.ENABLE_TRACE_LOG) {
-                WXLogUtils.d(WXRecyclerTemplateList.TAG, "WXTemplateList doSafeLayout " +
-                        component.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE) + " " + Thread.currentThread().getName() + " doSafeLayout  used " +
-                        (System.currentTimeMillis() - start));
-            }
-            if(!(height > 0)){
-                WXLogUtils.e(WXRecyclerTemplateList.TAG, " WXTemplateList doSafeLayout wrong template " +
-                        component.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE)  + " cell height " + height);
-            }
-        }catch (Exception e){
-            if(WXEnvironment.isApkDebugable()){
-                WXLogUtils.e(WXRecyclerTemplateList.TAG, e);
-            }
-        }
-    }
-
-
-    /**
-     * recursive set layout to component,
-     * dom extra will also be updated from dom object to component.
-     * if force is true, always set layout
-     * */
-    public static final void setLayout(WXComponent component, boolean force){
-        if(component.isWaste()){
-            return;
-        }
-        if(component.getAttrs().containsKey(TemplateDom.KEY_RESET_ANIMATION)){
-            if(WXUtils.getBoolean(component.getAttrs().get(TemplateDom.KEY_RESET_ANIMATION), true).booleanValue()){
-                TemplateDom.resetAnimaiton(component.getHostView());
-            }
-        }
-        long ptr = component.getRenderObjectPtr();
-        if(NativeRenderObjectUtils.nativeRenderObjectHasNewLayout(ptr)){
-            NativeRenderObjectUtils.nativeRenderObjectUpdateComponent(ptr, component);
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            int count = container.getChildCount();
-            for (int i = 0; i < count; ++i) {
-                WXComponent child = container.getChild(i);
-                if (child != null) {
-                    setLayout(child, force);
-                }
-            }
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java
deleted file mode 100644
index e19ff8b..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java
+++ /dev/null
@@ -1,701 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.binding;
-
-import android.os.Looper;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.bridge.EventResult;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.dom.binding.ELUtils;
-import com.taobao.weex.dom.binding.JSONUtils;
-import com.taobao.weex.dom.binding.WXStatement;
-import com.taobao.weex.el.parse.ArrayStack;
-import com.taobao.weex.el.parse.Operators;
-import com.taobao.weex.el.parse.Token;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.action.GraphicPosition;
-import com.taobao.weex.ui.action.GraphicSize;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXComponentFactory;
-import com.taobao.weex.ui.component.WXImage;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.component.list.template.CellDataManager;
-import com.taobao.weex.ui.component.list.template.CellRenderContext;
-import com.taobao.weex.ui.component.list.template.TemplateDom;
-import com.taobao.weex.ui.component.list.template.VirtualComponentLifecycle;
-import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
-import com.taobao.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Created by jianbai.gbj on 2017/8/17.
- * simple statement execute, render component for template list
- */
-public class Statements {
-
-
-    /**
-     * parse statements token from attrs and style and event
-     * */
-    public static void  parseStatementsToken(WXComponent component){
-        if(component.getBasicComponentData().isRenderPtrEmpty()){
-           component.getBasicComponentData().setRenderObjectPr(component.getRenderObjectPtr());
-        }
-        if(component.getBasicComponentData() != null){
-            BasicComponentData basicComponentData =  component.getBasicComponentData();
-            basicComponentData.getAttrs().parseStatements();
-            basicComponentData.getStyles().parseStatements();
-            basicComponentData.getEvents().parseStatements();
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            int count = container.getChildCount();
-            for (int i = 0; i < count; ++i) {
-                parseStatementsToken(container.getChild(i));
-            }
-        }
-    }
-
-
-
-    /**
-     * init component  if component is lazy,
-     * if component is not lazy, do nothing
-     * */
-    public static void initLazyComponent(WXComponent component, WXVContainer mParent){
-        if(component.isLazy() || component.getHostView() == null){
-            component.lazy(false);
-            if(mParent != null){
-                int index = mParent.indexOf(component);
-                mParent.createChildViewAt(index);
-            }else {
-                component.createView();
-            }
-            component.applyLayoutAndEvent(component);
-            component.bindData(component);
-        }
-    }
-
-
-
-    /**
-     * recursive copy component, none parent connect
-     * */
-    public static WXComponent copyComponentTree(WXComponent component){
-        WXComponent copy =  copyComponentTree(component, component.getParent());
-        return copy;
-    }
-
-    /**
-     * recursive copy component,
-     * */
-    private static final WXComponent copyComponentTree(WXComponent source, WXVContainer parent){
-        BasicComponentData basicComponentData = null;
-        try {
-            basicComponentData = source.getBasicComponentData().clone();
-        } catch (CloneNotSupportedException e) {
-            e.printStackTrace();
-        }
-        WXComponent component = WXComponentFactory.newInstance(source.getInstance(), parent, basicComponentData);
-        GraphicPosition graphicPosition = source.getLayoutPosition();
-        GraphicSize graphicSize = source.getLayoutSize();
-        component.updateDemission(graphicPosition.getTop(), graphicPosition.getBottom(), graphicPosition.getLeft(), graphicPosition.getRight(),
-                 graphicSize.getHeight(), graphicSize.getWidth());
-        component.updateExtra(source.getExtra());
-        if(source instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) source;
-            WXVContainer childParent = (WXVContainer) component;
-            int count = container.getChildCount();
-            for (int i = 0; i < count; ++i) {
-                WXComponent sourceChild = container.getChild(i);
-                if (sourceChild != null) {
-                    WXComponent targetChild = copyComponentTree(sourceChild,  childParent);childParent.addChild(targetChild);
-                    NativeRenderObjectUtils.nativeAddChildRenderObject(childParent.getRenderObjectPtr(),
-                            targetChild.getRenderObjectPtr());
-                }
-            }
-        }
-        //copy info need be sync
-        if(source.isWaste()){
-            component.setWaste(true);
-        }
-        return  component;
-    }
-
-    /**
-     *  @param component component with v-for statement, v-if statement and bind attrs
-     *  @param stack  execute context
-     *  render component in context, the function do the following  work.
-     *  execute component's v-for statement, v-if statement in context,
-     *  and rebuild component's tree with the statement, v-for reuse component execute by pre render.
-     *  if executed, component will be removed, don't remove, just mark it waste;
-     *  may be next render it can be used.
-     *  after statement has executed, render component's binding attrs in context and bind it to component.
-     * */
-    public static final List<WXComponent> doRender(WXComponent component, CellRenderContext stack){
-        List<WXComponent> updates = new ArrayList<>(4);
-        try{
-            doRenderComponent(component, stack, updates);
-        }catch (Exception e){
-            WXLogUtils.e("WeexStatementRender", e);
-        }
-        return updates;
-    }
-
-    public static final void doInitCompontent(List<WXComponent> updates) {
-        if(updates == null || updates.size() == 0){
-            return;
-        }
-        for(WXComponent renderNode : updates){
-            if(renderNode.getParent() == null){
-                throw new IllegalArgumentException("render node parent cann't find");
-            }
-            WXVContainer parent = renderNode.getParent();
-            int renderIndex = parent.indexOf(renderNode);
-            if(renderIndex < 0){
-                throw new IllegalArgumentException("render node cann't find");
-            }
-            parent.createChildViewAt(renderIndex);
-            renderNode.applyLayoutAndEvent(renderNode);
-            renderNode.bindData(renderNode);
-        }
-    }
-
-        /**
-         *  @param component component with v-for statement, v-if statement and bind attrs
-         *  @param context   execute context
-         *  render component in context, the function do the following  work.
-         *  execute component's v-for statement, v-if statement in context,
-         *  and rebuild component's tree with the statement, v-for reuse component execute by pre render.
-         *  if executed, component will be removed, don't remove, just mark it waste;
-         *  may be next render it can be used.
-         *  after statement has executed, render component's binding attrs in context and bind it to component.
-         * */
-    private static final int doRenderComponent(WXComponent component, CellRenderContext context,
-                                               List<WXComponent> updates){
-        WXVContainer parent = component.getParent();
-        WXAttr attrs = component.getAttrs();
-        WXStatement statement =  attrs.getStatement();
-        if(statement != null){
-            Token vif =  null;
-            JSONObject vfor = null;
-            if(statement.get(WXStatement.WX_IF) instanceof Token){
-                vif = (Token) statement.get(WXStatement.WX_IF);
-            }
-            if(statement.get(WXStatement.WX_FOR) instanceof  JSONObject){
-                vfor = (JSONObject) statement.get(WXStatement.WX_FOR);
-            }
-            // execute v-for content
-            if(vfor != null){
-                int    renderIndex = parent.indexOf(component);
-                if(vfor.get(WXStatement.WX_FOR_LIST) instanceof Token){
-                    Token listBlock = (Token) vfor.get(WXStatement.WX_FOR_LIST);
-                    String indexKey = vfor.getString(WXStatement.WX_FOR_INDEX);
-                    String itemKey = vfor.getString(WXStatement.WX_FOR_ITEM);
-                    Object data = null;
-                    if(listBlock != null) {
-                        data = listBlock.execute(context.stack);
-                    }
-                    if((data instanceof List || data instanceof  Map)){
-
-                        Collection collection = null;
-                        Map  map = null;
-                        if(data instanceof  List){
-                            collection = (List)data;
-                        }else{
-                            map = (Map)data;
-                            collection = map.keySet();
-                        }
-                        Map<String, Object> loop = new HashMap<>();
-                        int index = 0;
-                        for(Object item : collection){
-                            Object key = null;
-                            Object value = item;
-                            if(map == null){
-                                key = index;
-                                value = item;
-                                index ++;
-                            }else{
-                                key = item;
-                                value = map.get(item);
-                            }
-                            if(indexKey != null){
-                                loop.put(indexKey, key);
-                            }
-
-                            if(itemKey != null){
-                                loop.put(itemKey, value);
-                            }else{
-                                context.stack.push(value);
-                            }
-                            if(loop.size() > 0){
-                                context.stack.push(loop);
-                            }
-
-
-                            if(vif != null){
-                                if(!Operators.isTrue(vif.execute(context.stack))){
-                                    continue;
-                                }
-                            }
-                            //find resuable renderNode
-                            WXComponent renderNode = null;
-                            if(renderIndex < parent.getChildCount()){
-                                renderNode = parent.getChild(renderIndex);
-                                //check is same statment, if true, it is usabled.
-                                if(!isCreateFromNodeStatement(renderNode, component)){
-                                    renderNode = null;
-                                }
-                                if(renderNode != null){
-                                    if(renderNode.isWaste()){
-                                        renderNode.setWaste(false);
-                                    }
-                                }
-                            }
-                            //none resuable render node, create node, add to parent, but clear node's statement
-                            if(renderNode == null){
-                                long start = System.currentTimeMillis();
-                                renderNode = copyComponentTree(component, parent);
-                                renderNode.setWaste(false);
-                                if(renderNode.getAttrs().getStatement() != null) {
-                                    renderNode.getAttrs().getStatement().remove(WXStatement.WX_FOR);
-                                    renderNode.getAttrs().getStatement().remove(WXStatement.WX_IF); //clear node's statement
-                                }
-                                parent.addChild(renderNode, renderIndex);
-                                NativeRenderObjectUtils.nativeAddChildRenderObject(parent.getRenderObjectPtr(),
-                                        renderNode.getRenderObjectPtr());
-                                updates.add(renderNode);
-                                if(WXEnvironment.isApkDebugable()){
-                                    WXLogUtils.d(WXRecyclerTemplateList.TAG, Thread.currentThread().getName() +  renderNode.getRef() + renderNode.getComponentType() + "statements copy component tree used " + (System.currentTimeMillis() - start));
-                                }
-                            }
-                            doBindingAttrsEventAndRenderChildNode(renderNode, context, updates);
-                            renderIndex++;
-                            if(loop.size() > 0){
-                                context.stack.push(loop);
-                            }
-                            if(itemKey == null) {
-                                context.stack.pop();
-                            }
-                        }
-                    }
-                }else{
-                    WXLogUtils.e(WXRecyclerTemplateList.TAG,  vfor.toJSONString() + " not call vfor block, for pre compile");
-                }
-                //after v-for execute, remove component created pre v-for.
-                for(;renderIndex<parent.getChildCount(); renderIndex++){
-                    WXComponent wasteNode = parent.getChild(renderIndex);
-                    if(!isCreateFromNodeStatement(wasteNode, component)){
-                        break;
-                    }
-                    wasteNode.setWaste(true);
-                }
-                return renderIndex - parent.indexOf(component);
-            }
-
-            //execute v-if context
-            if(vif != null){
-                if(!Operators.isTrue(vif.execute(context.stack))){
-                    component.setWaste(true);
-                    return 1;
-                }else{
-                    component.setWaste(false);
-                }
-
-            }
-        }
-        doBindingAttrsEventAndRenderChildNode(component, context, updates);
-        return  1;
-    }
-
-
-    /**
-     * bind attrs and doRender component child
-     * */
-    private static void doBindingAttrsEventAndRenderChildNode(WXComponent component, CellRenderContext context,
-                                                              List<WXComponent> updates){
-        WXAttr attr = component.getAttrs();
-
-        /**
-         * sub component supported, sub component new stack
-         * */
-        ArrayStack stack = context.stack;
-
-
-        String virtualComponentId = null;
-        boolean callVirtualComponentAttach = false;
-        if(attr.get(ELUtils.IS_COMPONENT_ROOT) != null
-                && WXUtils.getBoolean(attr.get(ELUtils.IS_COMPONENT_ROOT), false)){
-            if(attr.get(ELUtils.COMPONENT_PROPS) != null
-                    && JSONUtils.isJSON(attr.get(ELUtils.COMPONENT_PROPS))){
-                 String compoentId = (String) attr.get(CellDataManager.SUB_COMPONENT_TEMPLATE_ID);
-                Object compoentData = null;
-                if(!TextUtils.isEmpty(compoentId)){
-                   virtualComponentId =  context.getRenderState().getVirtualComponentIds().get(component.getViewTreeKey());
-                   if(virtualComponentId == null){ //none virtualComponentId, create and do attach
-                        virtualComponentId =  CellDataManager.createVirtualComponentId(context.templateList.getRef(),
-                                component.getViewTreeKey(), context.templateList.getItemId(context.position));
-                        Map<String, Object>  props  = renderProps(JSONUtils.toJSON(attr.get(ELUtils.COMPONENT_PROPS)), context.stack);
-                        EventResult result = WXBridgeManager.getInstance().syncCallJSEventWithResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, compoentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.CREATE,  new Object[]{
-                                virtualComponentId,
-                                props
-                        }, null);
-                        if(result != null
-                                && result.getResult() != null
-                                && result.getResult() instanceof Map){
-                            props.putAll((Map<? extends String, ?>) result.getResult());
-                        }
-                        compoentData  =  props;
-                        context.getRenderState().getVirtualComponentIds().put(component.getViewTreeKey(), virtualComponentId);
-                        context.templateList.getCellDataManager().createVirtualComponentData(context.position, virtualComponentId, compoentData);
-                         callVirtualComponentAttach = true; // when first create virtual compoent, call create
-                     }else{ // get virtual component data check has dirty's update
-                       compoentData = context.getRenderState().getVirtualComponentDatas().get(virtualComponentId);
-                       if(context.getRenderState().isHasDataUpdate()){
-                           Map<String, Object>  props  = renderProps((JSONObject) attr.get(ELUtils.COMPONENT_PROPS), context.stack);
-                           EventResult result = WXBridgeManager.getInstance().syncCallJSEventWithResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.SYNSTATE,  new Object[]{
-                                   virtualComponentId,
-                                   props
-                           }, null);
-
-                           if(result != null
-                                   && result.getResult() != null
-                                   && result.getResult() instanceof Map){
-                               props.putAll((Map<? extends String, ?>) result.getResult());
-                               context.templateList.getCellDataManager().updateVirtualComponentData(virtualComponentId, props);
-                               compoentData = props;
-                           }
-                       }
-                    }
-                    component.getAttrs().put(CellDataManager.VIRTUAL_COMPONENT_ID, virtualComponentId);
-                }else{ //stateless component
-                    Map<String, Object>  props  = renderProps((JSONObject) attr.get(ELUtils.COMPONENT_PROPS), context.stack);
-                    compoentData = props;
-                }
-                //virtual component is new context
-                context.stack = new ArrayStack();
-                if(compoentData != null){
-                    context.stack.push(compoentData);
-                }
-            }
-        }
-
-        /**
-         * check node is render only once, if render once, and has rendered, just return
-         * */
-        Object vonce = null;
-        if(attr.getStatement() != null){
-            vonce = attr.getStatement().get(WXStatement.WX_ONCE);
-        }
-        if(vonce != null){
-            ArrayStack onceStack = context.getRenderState().getOnceComponentStates().get(component.getViewTreeKey());
-            if(onceStack == null){
-                onceStack = context.templateList.copyStack(context, stack);
-                context.getRenderState().getOnceComponentStates().put(component.getViewTreeKey(), onceStack);
-            }
-            context.stack = onceStack;
-        }
-
-        doRenderBindingAttrsAndEvent(component, context);
-        if(component instanceof WXVContainer){
-            if(component.isWaste()){
-                if(!(component instanceof WXCell)){
-                     return;
-                }
-            }
-            WXVContainer container = (WXVContainer) component;
-            for(int k=0; k<container.getChildCount();){
-                WXComponent next = container.getChild(k);
-                k += doRenderComponent(next, context, updates);
-            }
-        }
-        if(stack != context.stack){
-            context.stack = stack;
-        }
-        //create virtual componentId
-        if(callVirtualComponentAttach && virtualComponentId != null){
-            WXBridgeManager.getInstance().asyncCallJSEventVoidResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.ATTACH, new Object[]{
-                    TemplateDom.findAllComponentRefs(context.templateList.getRef(),context.position, component)
-            });
-        }
-     }
-
-
-    /**
-     * check whether render node is create from component node statement.
-     * */
-    private static boolean isCreateFromNodeStatement(WXComponent renderNode, WXComponent component){
-        return (renderNode.getRef() != null && renderNode.getRef().equals(component.getRef()));
-    }
-
-
-    /**
-     * render dynamic binding attrs and bind them to component node.
-     * */
-    private static void doRenderBindingAttrsAndEvent(WXComponent component, CellRenderContext context){
-        ArrayStack stack  = context.stack;
-        component.setWaste(false);
-        WXAttr attr = component.getAttrs();
-        if(attr != null
-                && attr.getBindingAttrs() != null
-                && attr.getBindingAttrs().size() > 0){
-            ArrayMap<String, Object> bindAttrs = component.getAttrs().getBindingAttrs();
-            Map<String, Object> dynamic =  renderBindingAttrs(bindAttrs, stack);
-            Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
-            /**
-             * diff attrs, see attrs has update, remove none update attrs
-             * */
-            Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
-            while (iterator.hasNext()){
-                Map.Entry<String, Object> entry = iterator.next();
-                String key = entry.getKey();
-                Object value = entry.getValue();
-                Object oldValue = attr.get(key);
-                if(value == null){
-                    if(oldValue == null){
-                        iterator.remove();
-                        continue;
-                    }
-                }else{
-                    if(value.equals(oldValue)){
-                        iterator.remove();
-                    }
-                }
-            }
-
-            if(dynamic.size() > 0) {
-                if(dynamic.size() == 1
-                        && dynamic.get(Constants.Name.SRC) != null
-                        && component instanceof WXImage){
-                    //for image avoid dirty layout, only update src attrs
-                    component.getAttrs().put(Constants.Name.SRC, dynamic.get(Constants.Name.SRC));
-                }else {
-                    component.nativeUpdateAttrs(dynamic);
-                }
-                if(isMainThread()) {
-                    component.updateProperties(dynamic);
-                }
-                dynamic.clear();
-            }
-        }
-
-
-        WXStyle style = component.getStyles();
-        if(style != null && style.getBindingStyle() != null){
-            ArrayMap<String, Object> bindStyle = style.getBindingStyle();
-            Map<String, Object> dynamic =  renderBindingAttrs(bindStyle, stack);
-            Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
-            /**
-             * diff attrs, see attrs has update, remove none update attrs
-             * */
-            Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
-            while (iterator.hasNext()){
-                Map.Entry<String, Object> entry = iterator.next();
-                String key = entry.getKey();
-                Object value = entry.getValue();
-                Object oldValue = style.get(key);
-                if(value == null){
-                    if(oldValue == null){
-                        iterator.remove();
-                        continue;
-                    }
-                }else{
-                    if(value.equals(oldValue)){
-                        iterator.remove();
-                    }
-                }
-            }
-            if(dynamic.size() > 0) {
-                  component.updateNativeStyles(dynamic);
-                 if(isMainThread()) {
-                    component.updateProperties(dynamic);
-                 }
-            }
-        }
-
-        WXEvent event = component.getEvents();
-        if(event == null || event.getEventBindingArgs() == null){
-            return;
-        }
-        Set<Map.Entry<String, Object>> eventBindArgsEntrySet = event.getEventBindingArgs().entrySet();
-        for(Map.Entry<String, Object> eventBindArgsEntry : eventBindArgsEntrySet){
-             List<Object> values = getBindingEventArgs(stack, eventBindArgsEntry.getValue());
-             if(values != null){
-                 event.putEventBindingArgsValue(eventBindArgsEntry.getKey(), values);
-             }
-        }
-
-    }
-
-
-    /**
-     * @param  bindAttrs  none null,
-     * @param  context  context
-     * return binding attrs rended value in context
-     * */
-    private static final  ThreadLocal<Map<String, Object>> dynamicLocal = new ThreadLocal<>();
-    public static Map<String, Object> renderBindingAttrs(ArrayMap bindAttrs, ArrayStack stack){
-        Set<Map.Entry<String, Object>> entrySet = bindAttrs.entrySet();
-        Map<String, Object> dynamic = dynamicLocal.get();
-        if(dynamic == null) {
-            dynamic = new HashMap<>();
-            dynamicLocal.set(dynamic);
-        }
-        if(dynamic.size() > 0){
-            dynamic.clear();
-        }
-        for(Map.Entry<String, Object> entry : entrySet){
-            Object value = entry.getValue();
-            String key = entry.getKey();
-            if(value instanceof  JSONObject
-                    && (((JSONObject) value).get(ELUtils.BINDING)  instanceof Token)){
-                JSONObject binding = (JSONObject) value;
-                Token block = (Token) (binding.get(ELUtils.BINDING));
-                Object blockValue = block.execute(stack);
-                dynamic.put(key, blockValue);
-            }else if(value instanceof JSONArray){
-                JSONArray array = (JSONArray) value;
-                StringBuilder builder = new StringBuilder();
-                for(int i=0; i<array.size(); i++){
-                    Object element = array.get(i);
-                    if(element instanceof  CharSequence){
-                        builder.append(element);
-                        continue;
-                    }
-                    if(element instanceof JSONObject
-                            && (((JSONObject) element).get(ELUtils.BINDING) instanceof Token)){
-                        JSONObject binding = (JSONObject) element;
-                        Token block = (Token) (binding.get(ELUtils.BINDING));
-                        Object blockValue = block.execute(stack);
-                        if(blockValue == null){
-                            blockValue = "";
-                        }
-                        builder.append(blockValue);
-                    }
-                }
-                String builderString = builder.toString();
-                if(builderString.length() > 256){
-                    if(WXEnvironment.isApkDebugable()){
-                        WXLogUtils.w(WXRecyclerTemplateList.TAG, " warn too big string " + builderString);
-                    }
-                }
-                dynamic.put(key, builderString);
-            }
-        }
-        return  dynamic;
-    }
-
-
-    public static Map<String, Object> renderProps(JSONObject props, ArrayStack stack){
-        Set<Map.Entry<String, Object>> entrySet = props.entrySet();
-        Map<String, Object> renderProps = new ArrayMap<>(4);
-        for(Map.Entry<String, Object> entry : entrySet){
-            Object value = entry.getValue();
-            String key = entry.getKey();
-            if(value instanceof  JSONObject
-                    && (((JSONObject) value).get(ELUtils.BINDING)  instanceof Token)){
-                JSONObject binding = (JSONObject) value;
-                Token block = (Token) (binding.get(ELUtils.BINDING));
-                Object blockValue = block.execute(stack);
-                renderProps.put(key, blockValue);
-            }else{
-                renderProps.put(key, value);
-            }
-        }
-        return  renderProps;
-    }
-
-    public static List<Object> getBindingEventArgs(ArrayStack stack, Object bindings){
-          List<Object>  params = new ArrayList<>(4);
-          if(bindings instanceof  JSONArray){
-              JSONArray array = (JSONArray) bindings;
-              for(int i=0; i<array.size(); i++){
-                  Object value = array.get(i);
-                  if(value instanceof  JSONObject
-                          && (((JSONObject) value).get(ELUtils.BINDING) instanceof Token)){
-                      Token block = (Token)(((JSONObject) value).get(ELUtils.BINDING));
-                      Object blockValue = block.execute(stack);
-                      params.add(blockValue);
-                  }else{
-                      params.add(value);
-                  }
-              }
-          }else if(bindings instanceof  JSONObject){
-              JSONObject binding = (JSONObject) bindings;
-               if(binding.get(ELUtils.BINDING) instanceof Token){
-                   Token block = (Token) binding.get(ELUtils.BINDING);
-                   Object blockValue = block.execute(stack);
-                   params.add(blockValue);
-               }else{
-                   params.add(bindings.toString());
-               }
-          }else{
-              params.add(bindings.toString());
-          }
-          return  params;
-    }
-
-
-    private static boolean isMainThread(){
-        return  Thread.currentThread() == Looper.getMainLooper().getThread();
-    }
-
-
-
-    public static String getComponentId(WXComponent component){
-        if(component instanceof WXCell || component == null){
-            return  null;
-        }
-        WXAttr attr = component.getAttrs();
-        if(attr.get(ELUtils.IS_COMPONENT_ROOT) != null
-                && WXUtils.getBoolean(attr.get(ELUtils.IS_COMPONENT_ROOT), false)){
-            if(attr.get(ELUtils.COMPONENT_PROPS) != null
-                    && attr.get(ELUtils.COMPONENT_PROPS) instanceof  JSONObject){
-                Object componentId = attr.get(CellDataManager.VIRTUAL_COMPONENT_ID);
-                if(componentId == null){
-                    return null;
-                }
-                return componentId.toString();
-            }
-        }
-        return getComponentId(component.getParent());
-    }
-
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java
deleted file mode 100644
index 29eb775..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.helper;
-
-import android.os.Handler;
-import android.os.Looper;
-
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.OnWXScrollListener;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXScroller;
-import com.taobao.weex.ui.component.list.BasicListComponent;
-import com.taobao.weex.ui.component.list.ListComponentView;
-import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.Map;
-
-
-/**
- * Created by furture on 2017/11/13.
- */
-
-public class ScrollStartEndHelper implements Runnable{
-
-    private Handler handler;
-    private WXComponent component;
-    private boolean  hasStart;
-    private boolean  canStart = false;
-
-    private long  minInterval;
-    private int oldState = OnWXScrollListener.IDLE;
-
-    private int x;
-    private int y;
-    private boolean hasScrollEnd;
-
-
-    public ScrollStartEndHelper(WXComponent component) {
-        this.component = component;
-        this.handler = new Handler(Looper.getMainLooper());
-        this.minInterval = WXUtils.getNumberInt(component.getAttrs().get("minscrolldelayinterval"), 32);
-    }
-
-    /**
-     * @param  x scroll offset or dx, which is not accurate
-     * @param  y scroll offset or dy, which is not accurate
-     * */
-    public void  onScrolled(int x, int y){
-        if((component.getEvents().contains(Constants.Event.SCROLL_START)
-                || component.getEvents().contains(Constants.Event.SCROLL_END))){
-            this.x = x;
-            this.y = y;
-            if(!hasStart && canStart){
-                if(component.getEvents().contains(Constants.Event.SCROLL_START)){
-                    Map<String, Object> event = getScrollEvent(x,y);
-                    if (null !=event && !event.isEmpty()){
-                        component.fireEvent(Constants.Event.SCROLL_START,event);
-
-                    }
-                }
-                hasStart = true;
-                canStart = false;
-            }
-            handler.removeCallbacks(this);
-            handler.postDelayed(this, minInterval);
-        }
-    }
-
-
-    @Override
-    public void run() {
-        if(component.isDestoryed()){
-            return;
-        }
-        if(!hasScrollEnd){
-            return;
-        }
-        if(canStart){
-            component.fireEvent(Constants.Event.SCROLL_START, getScrollEvent(this.x, this.y));
-            canStart = false;
-        }
-        if(component.getEvents().contains(Constants.Event.SCROLL_END)){
-            component.fireEvent(Constants.Event.SCROLL_END, getScrollEvent(this.x, this.y));
-
-        }
-        hasStart = false;
-        hasScrollEnd = false;
-
-    }
-
-    private Map<String, Object> getScrollEvent(int offsetX, int offsetY){
-        if(component instanceof BasicListComponent){
-            BasicListComponent basicListComponent = (BasicListComponent) component;
-            if(basicListComponent.getHostView() instanceof ListComponentView){
-                ListComponentView componentView = (ListComponentView) basicListComponent.getHostView();
-                if(componentView != null){
-                    return basicListComponent.getScrollEvent(componentView.getInnerView(), offsetX, offsetY);
-                }
-            }
-        }else if(component instanceof WXRecyclerTemplateList){
-            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) component;
-            return templateList.getScrollEvent(templateList.getHostView().getInnerView(), offsetX, offsetY);
-        }else if(component instanceof WXScroller){
-            WXScroller scroller = (WXScroller) component;
-            return scroller.getScrollEvent(offsetX, offsetY);
-        }
-        return null;
-    }
-
-    public void onScrollStateChanged(int newState){
-
-        if(oldState == OnWXScrollListener.IDLE){
-            canStart = true;
-        }
-
-        if(newState == OnWXScrollListener.IDLE){
-            hasScrollEnd = true;
-            handler.removeCallbacks(this);
-            handler.postDelayed(this, minInterval);
-        }
-
-        oldState = newState;
-    }
-
-
-    public static boolean isScrollEvent(String type){
-        if(Constants.Event.SCROLL.equals(type)){
-            return  true;
-        }else if(Constants.Event.SCROLL_START.equals(type)){
-            return  true;
-        }else if(Constants.Event.SCROLL_END.equals(type)){
-            return  true;
-        }
-        return  false;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/SoftKeyboardDetector.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/SoftKeyboardDetector.java
deleted file mode 100644
index afbabd0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/SoftKeyboardDetector.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.helper;
-
-import android.app.Activity;
-import android.graphics.Rect;
-import android.os.Build;
-import android.support.annotation.Nullable;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.WindowManager;
-
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Created by moxun on 17/3/24.
- */
-
-public class SoftKeyboardDetector {
-
-    private static final int KEYBOARD_VISIBLE_THRESHOLD_DIP = 100;
-
-    public static Unregister registerKeyboardEventListener(Activity activity, final OnKeyboardEventListener listener) {
-        if (activity == null || listener == null) {
-            WXLogUtils.e("Activity or listener is null!");
-            return null;
-        }
-
-        if (activity.getWindow() != null) {
-            WindowManager.LayoutParams attributes = activity.getWindow().getAttributes();
-            if (attributes != null) {
-                int softInputMode = attributes.softInputMode;
-                if (softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
-                        || softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) {
-                    WXLogUtils.e("SoftKeyboard detector can't work with softInputMode is SOFT_INPUT_ADJUST_NOTHING or SOFT_INPUT_ADJUST_PAN");
-                    return null;
-                }
-            }
-        }
-
-        final View activityRoot = getActivityRoot(activity);
-
-        if (activityRoot == null) {
-            WXLogUtils.e("Activity root is null!");
-            return null;
-        }
-
-        final ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
-
-            private final Rect visibleFrame = new Rect();
-            private final int threshold = WXViewUtils.dip2px(KEYBOARD_VISIBLE_THRESHOLD_DIP);
-            private boolean wasKeyboardOpened = false;
-
-            @Override
-            public void onGlobalLayout() {
-                activityRoot.getWindowVisibleDisplayFrame(visibleFrame);
-                int heightDiff = activityRoot.getRootView().getHeight() - visibleFrame.height();
-                boolean isOpen = heightDiff > threshold;
-                if (isOpen == wasKeyboardOpened) {
-                    return;
-                }
-
-                wasKeyboardOpened = isOpen;
-                listener.onKeyboardEvent(isOpen);
-            }
-        };
-
-        activityRoot.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
-        return new DefaultUnRegister(activity, layoutListener);
-    }
-
-    public static boolean isKeyboardVisible(Activity activity) {
-        Rect windowFrame = new Rect();
-        View root = getActivityRoot(activity);
-
-        if (root != null) {
-            root.getWindowVisibleDisplayFrame(windowFrame);
-            int heightDiff = root.getRootView().getHeight() - windowFrame.height();
-            return heightDiff > WXViewUtils.dip2px(KEYBOARD_VISIBLE_THRESHOLD_DIP);
-        }
-        return false;
-    }
-
-    public static @Nullable View getActivityRoot(Activity activity) {
-        if (activity != null) {
-            return activity.findViewById(android.R.id.content);
-        }
-        return null;
-    }
-
-    public static final class DefaultUnRegister implements Unregister {
-
-        private WeakReference<Activity> activityRef;
-        private WeakReference<ViewTreeObserver.OnGlobalLayoutListener> listenerRef;
-
-        public DefaultUnRegister(Activity activity, ViewTreeObserver.OnGlobalLayoutListener listener) {
-            this.activityRef = new WeakReference<>(activity);
-            this.listenerRef = new WeakReference<>(listener);
-        }
-
-        @Override
-        public void execute() {
-            Activity activity = activityRef.get();
-            ViewTreeObserver.OnGlobalLayoutListener listener = listenerRef.get();
-
-            if (activity != null && listener != null) {
-                View root = SoftKeyboardDetector.getActivityRoot(activity);
-                if (root != null) {
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-                        root.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
-                    } else {
-                        root.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
-                    }
-                }
-            }
-
-            activityRef.clear();
-            listenerRef.clear();
-        }
-    }
-
-    public interface Unregister {
-        void execute();
-    }
-
-    public interface OnKeyboardEventListener {
-        void onKeyboardEvent(boolean isShown);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/WXStickyHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/WXStickyHelper.java
deleted file mode 100644
index fca3c14..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/WXStickyHelper.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.helper;
-
-import com.taobao.weex.ui.component.Scrollable;
-import com.taobao.weex.ui.component.WXComponent;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Created by miomin on 16/7/7.
- */
-public class WXStickyHelper {
-
-    private Scrollable scrollable;
-
-    public WXStickyHelper(Scrollable scrollable) {
-        this.scrollable = scrollable;
-    }
-
-    public void bindStickStyle(WXComponent component, Map<String, Map<String, WXComponent>> mStickyMap) {
-        Scrollable scroller = component.getParentScroller();
-        if (scroller == null) {
-            return;
-        }
-        Map<String, WXComponent> stickyMap = mStickyMap.get(scroller
-                .getRef());
-        if (stickyMap == null) {
-            stickyMap = new ConcurrentHashMap<>();
-        }
-        if (stickyMap.containsKey(component.getRef())) {
-            return;
-        }
-        stickyMap.put(component.getRef(), component);
-        mStickyMap.put(scroller.getRef(), stickyMap);
-    }
-
-    public void unbindStickStyle(WXComponent component, Map<String, Map<String, WXComponent>> mStickyMap) {
-        Scrollable scroller = component.getParentScroller();
-        if (scroller == null) {
-            return;
-        }
-        Map<String, WXComponent> stickyMap = mStickyMap.get(scroller
-                .getRef());
-        if (stickyMap == null) {
-            return;
-        }
-        stickyMap.remove(component.getRef());
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/WXTimeInputHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/WXTimeInputHelper.java
deleted file mode 100644
index d666439..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/WXTimeInputHelper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.helper;
-
-import android.support.annotation.Nullable;
-import android.widget.TextView;
-
-import com.taobao.weex.appfram.pickers.DatePickerImpl;
-import com.taobao.weex.ui.component.AbstractEditComponent;
-
-/**
- * Created by moxun on 16/10/12.
- */
-
-public class WXTimeInputHelper {
-  public static void pickDate(String max, String min, final AbstractEditComponent component) {
-    final TextView target = component.getHostView();
-
-    DatePickerImpl.pickDate(
-            target.getContext(),
-            target.getText().toString(),
-            max,
-            min,
-            new DatePickerImpl.OnPickListener() {
-              @Override
-              public void onPick(boolean set, @Nullable String result) {
-                if (set) {
-                  target.setText(result);
-                  component.performOnChange(result);
-                }
-              }
-            },
-            null);
-  }
-
-  public static void pickTime(final AbstractEditComponent component) {
-    final TextView target = component.getHostView();
-
-    DatePickerImpl.pickTime(
-            target.getContext(),
-            target.getText().toString(),
-            new DatePickerImpl.OnPickListener() {
-              @Override
-              public void onPick(boolean set, @Nullable String result) {
-                if (set) {
-                  target.setText(result);
-                  component.performOnChange(result);
-                }
-              }
-            },
-            null
-    );
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
deleted file mode 100644
index 0db53a8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
+++ /dev/null
@@ -1,1475 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.text.TextUtils;
-import android.util.SparseArray;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.ICheckBindingScroller;
-import com.taobao.weex.common.OnWXScrollListener;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.AppearanceHelper;
-import com.taobao.weex.ui.component.Scrollable;
-import com.taobao.weex.ui.component.WXBaseRefresh;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXComponentProp;
-import com.taobao.weex.ui.component.WXHeader;
-import com.taobao.weex.ui.component.WXLoading;
-import com.taobao.weex.ui.component.WXRefresh;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.component.helper.ScrollStartEndHelper;
-import com.taobao.weex.ui.component.helper.WXStickyHelper;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-import com.taobao.weex.ui.view.listview.adapter.IOnLoadMoreListener;
-import com.taobao.weex.ui.view.listview.adapter.IRecyclerAdapterListener;
-import com.taobao.weex.ui.view.listview.adapter.ListBaseViewHolder;
-import com.taobao.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
-import com.taobao.weex.ui.view.listview.adapter.WXRecyclerViewOnScrollListener;
-import com.taobao.weex.ui.view.refresh.wrapper.BounceRecyclerView;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-/**
- * Created by sospartan on 13/12/2016.
- */
-
-public abstract class BasicListComponent<T extends ViewGroup & ListComponentView> extends WXVContainer<T> implements
-    IRecyclerAdapterListener<ListBaseViewHolder>, IOnLoadMoreListener, Scrollable {
-  public static final String TRANSFORM = "transform";
-  public static final String LOADMOREOFFSET = "loadmoreoffset";
-  private String TAG = "BasicListComponent";
-  private int mListCellCount = 0;
-  private boolean mForceLoadmoreNextTime = false;
-  private static final Pattern transformPattern = Pattern.compile("([a-z]+)\\(([0-9\\.]+),?([0-9\\.]+)?\\)");
-
-  private Map<String, AppearanceHelper> mAppearComponents = new HashMap<>();
-  private Runnable mAppearChangeRunnable = null;
-  private long mAppearChangeRunnableDelay = 50;
-
-  private boolean isScrollable = true;
-  private ArrayMap<String, Long> mRefToViewType;
-  private SparseArray<ArrayList<WXComponent>> mViewTypes;
-  private WXRecyclerViewOnScrollListener mViewOnScrollListener = new WXRecyclerViewOnScrollListener(this);
-
-  private static final int MAX_VIEWTYPE_ALLOW_CACHE = 9;
-  private static boolean mAllowCacheViewHolder = true;
-  private static boolean mDownForBidCacheViewHolder = false;
-
-
-  protected int mLayoutType = WXRecyclerView.TYPE_LINEAR_LAYOUT;
-  protected int mColumnCount = 1;
-  protected float mColumnGap = 0;
-  protected float mColumnWidth = 0;
-  protected float mLeftGap = 0;
-  protected float mRightGap = 0;
-
-  private int mOffsetAccuracy = 10;
-  private Point mLastReport = new Point(-1, -1);
-  private boolean mHasAddScrollEvent = false;
-
-  private RecyclerView.ItemAnimator mItemAnimator;
-
-  private DragHelper mDragHelper;
-
-  /**
-   * exclude cell when dragging(attributes for cell)
-   */
-  private static final String EXCLUDED = "dragExcluded";
-
-  /**
-   * the type to trigger drag-drop
-   */
-  private static final String DRAG_TRIGGER_TYPE = "dragTriggerType";
-
-  private static final String DEFAULT_TRIGGER_TYPE = DragTriggerType.LONG_PRESS;
-  private static final boolean DEFAULT_EXCLUDED = false;
-
-  private static final String DRAG_ANCHOR = "dragAnchor";
-
-  /**
-   * gesture type which can trigger drag&drop
-   */
-  interface DragTriggerType {
-    String PAN = "pan";
-    String LONG_PRESS = "longpress";
-  }
-
-  private String mTriggerType;
-
-  /**
-   * Map for storing component that is sticky.
-   **/
-  private Map<String, Map<String, WXComponent>> mStickyMap = new HashMap<>();
-  private WXStickyHelper stickyHelper;
-
-  /**
-   * scroll start and scroll end event
-   * */
-  private ScrollStartEndHelper mScrollStartEndHelper;
-
-  /**
-   * keep positon
-   * */
-  private  WXComponent keepPositionCell = null;
-  private  Runnable keepPositionCellRunnable = null;
-  private  long keepPositionLayoutDelay = 150;
-
-
-  public BasicListComponent(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-    stickyHelper = new WXStickyHelper(this);
-  }
-
-  @SuppressLint("RtlHardcoded")
-  @Override
-  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
-    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-      lp.setMargins(left, top, right, bottom);
-      lp.setMarginStart(left);
-      lp.setMarginEnd(right);
-    } else {
-      if (lp instanceof FrameLayout.LayoutParams) {
-        FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
-        if (this.isLayoutRTL()) {
-          lp_frameLayout.gravity = Gravity.RIGHT | Gravity.TOP;
-          lp.setMargins(right, top, left, bottom);
-        } else {
-          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
-          lp.setMargins(left, top, right, bottom);
-        }
-      } else {
-        lp.setMargins(left, top, right, bottom);
-      }
-    }
-  }
-
-  @Override
-  public void setLayout(WXComponent component) {
-    if (component.getHostView() != null) {
-      int layoutDirection = component.isLayoutRTL() ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
-      ViewCompat.setLayoutDirection(component.getHostView(), layoutDirection);
-    }
-    super.setLayout(component);
-  }
-
-  @Override
-  protected void onHostViewInitialized(T host) {
-    super.onHostViewInitialized(host);
-
-    WXRecyclerView recyclerView = host.getInnerView();
-    if (recyclerView == null || recyclerView.getAdapter() == null) {
-      WXLogUtils.e(TAG, "RecyclerView is not found or Adapter is not bound");
-      return;
-    }
-    if(WXUtils.getBoolean(getAttrs().get("prefetchGapDisable"), false)){
-      if(recyclerView.getLayoutManager() != null){
-        recyclerView.getLayoutManager().setItemPrefetchEnabled(false);
-      }
-    }
-
-    if (mChildren == null) {
-      WXLogUtils.e(TAG, "children is null");
-      return;
-    }
-
-    mDragHelper = new DefaultDragHelper(mChildren, recyclerView, new EventTrigger() {
-      @Override
-      public void triggerEvent(String type, Map<String, Object> args) {
-        fireEvent(type, args);
-      }
-    });
-
-    mTriggerType = getTriggerType(this);
-  }
-
-  /**
-   * Measure the size of the recyclerView.
-   *
-   * @param width  the expected width
-   * @param height the expected height
-   * @return the result of measurement
-   */
-  @Override
-  protected MeasureOutput measure(int width, int height) {
-    int screenH = WXViewUtils.getScreenHeight(getInstanceId());
-    int weexH = WXViewUtils.getWeexHeight(getInstanceId());
-    int outHeight = height > (weexH >= screenH ? screenH : weexH) ? weexH - getAbsoluteY() : height;
-    return super.measure(width, outHeight);
-  }
-
-  public int getOrientation() {
-    return Constants.Orientation.VERTICAL;
-  }
-
-  @Override
-  public void destroy() {
-    if(mAppearChangeRunnable != null &&  getHostView() != null) {
-      getHostView().removeCallbacks(mAppearChangeRunnable);
-      mAppearChangeRunnable = null;
-    }
-    super.destroy();
-    if (mStickyMap != null)
-      mStickyMap.clear();
-    if (mViewTypes != null)
-      mViewTypes.clear();
-    if (mRefToViewType != null)
-      mRefToViewType.clear();
-
-  }
-
-  @Override
-  public ViewGroup.LayoutParams getChildLayoutParams(WXComponent child, View hostView, int width, int height, int left, int right, int top, int bottom) {
-    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) hostView.getLayoutParams();
-    if (child instanceof WXBaseRefresh && params == null) {
-      params = new LinearLayout.LayoutParams(width, height);
-    } else if (params == null) {
-      params = new RecyclerView.LayoutParams(width, height);
-    } else {
-      params.width = width;
-      params.height = height;
-
-      this.setMarginsSupportRTL(params, left, 0, right, 0);
-    }
-    return params;
-  }
-
-  abstract T generateListView(Context context, int orientation);
-
-  @Override
-  protected T initComponentHostView(@NonNull Context context) {
-    T bounceRecyclerView = generateListView(context, getOrientation());
-
-    String transforms = getAttrByKey(TRANSFORM);
-    if (transforms != null) {
-      bounceRecyclerView.getInnerView().addItemDecoration(RecyclerTransform.parseTransforms(getOrientation(), transforms));
-    }
-    if(getAttrs().get(Constants.Name.KEEP_POSITION_LAYOUT_DELAY) != null){
-      keepPositionLayoutDelay = WXUtils.getNumberInt(getAttrs().get(Constants.Name.KEEP_POSITION_LAYOUT_DELAY), (int)keepPositionLayoutDelay);
-    }
-    if(getAttrs().get("appearActionDelay") != null){
-      mAppearChangeRunnableDelay =  WXUtils.getNumberInt(getAttrs().get("appearActionDelay"), (int) mAppearChangeRunnableDelay);
-    }
-
-    mItemAnimator=bounceRecyclerView.getInnerView().getItemAnimator();
-
-    RecyclerViewBaseAdapter recyclerViewBaseAdapter = new RecyclerViewBaseAdapter<>(this);
-    recyclerViewBaseAdapter.setHasStableIds(true);
-    bounceRecyclerView.setRecyclerViewBaseAdapter(recyclerViewBaseAdapter);
-    bounceRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
-    bounceRecyclerView.getInnerView().addOnScrollListener(mViewOnScrollListener);
-    if(getAttrs().get(Constants.Name.HAS_FIXED_SIZE) != null){
-      boolean hasFixedSize = WXUtils.getBoolean(getAttrs().get(Constants.Name.HAS_FIXED_SIZE), false);
-      bounceRecyclerView.getInnerView().setHasFixedSize(hasFixedSize);
-    }
-
-    bounceRecyclerView.getInnerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
-      @Override
-      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-        super.onScrollStateChanged(recyclerView, newState);
-        getScrollStartEndHelper().onScrollStateChanged(newState);
-        List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
-        int size;
-        OnWXScrollListener listener;
-        if (listeners != null && (size = listeners.size()) > 0) {
-          for (int i=0; i<size; ++i) {
-            if(i >= listeners.size()){
-              break;
-            }
-            listener = listeners.get(i);
-            if (listener != null) {
-              View topView = recyclerView.getChildAt(0);
-              if (topView != null) {
-                int y = topView.getTop();
-                listener.onScrollStateChanged(recyclerView, 0, y, newState);
-              }
-            }
-          }
-        }
-      }
-
-      @Override
-      public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-        super.onScrolled(recyclerView, dx, dy);
-        List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
-        if (listeners != null && listeners.size() > 0) {
-          try {
-            for (OnWXScrollListener listener : listeners) {
-              if (listener != null) {
-                if (listener instanceof ICheckBindingScroller) {
-                  if (((ICheckBindingScroller) listener).isNeedScroller(getRef(), null)) {
-                    listener.onScrolled(recyclerView, dx, dy);
-                  }
-                } else {
-                  listener.onScrolled(recyclerView, dx, dy);
-                }
-              }
-            }
-          } catch (Exception e) {
-            e.printStackTrace();
-          }
-        }
-      }
-    });
-
-    bounceRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
-      @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-      @Override
-      public void onGlobalLayout() {
-        T view;
-        if ((view = getHostView()) == null)
-          return;
-        mViewOnScrollListener.onScrolled(view.getInnerView(), 0, 0);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-          view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
-        } else {
-          view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
-        }
-      }
-    });
-    return bounceRecyclerView;
-  }
-
-  @Override
-  public void bindStickStyle(WXComponent component) {
-    stickyHelper.bindStickStyle(component, mStickyMap);
-  }
-
-  @Override
-  public void unbindStickStyle(WXComponent component) {
-    stickyHelper.unbindStickStyle(component, mStickyMap);
-    WXHeader cell = (WXHeader) findTypeParent(component, WXHeader.class);
-    if(cell != null && getHostView() != null) {
-      getHostView().notifyStickyRemove(cell);
-    }
-  }
-
-  private
-  @Nullable
-  WXComponent findDirectListChild(WXComponent comp) {
-    WXComponent parent;
-    if (comp == null || (parent = comp.getParent()) == null) {
-      return null;
-    }
-
-    if (parent instanceof BasicListComponent) {
-      return comp;
-    }
-
-    return findDirectListChild(parent);
-  }
-
-  @Override
-  protected boolean setProperty(String key, Object param) {
-    switch (key) {
-      case LOADMOREOFFSET:
-        return true;
-      case Constants.Name.SCROLLABLE:
-        boolean scrollable = WXUtils.getBoolean(param, true);
-        setScrollable(scrollable);
-        return true;
-      case Constants.Name.OFFSET_ACCURACY:
-        int accuracy = WXUtils.getInteger(param, 10);
-        setOffsetAccuracy(accuracy);
-        return true;
-      case Constants.Name.DRAGGABLE:
-        boolean draggable = WXUtils.getBoolean(param,false);
-        setDraggable(draggable);
-        return true;
-      case Constants.Name.SHOW_SCROLLBAR:
-        Boolean result = WXUtils.getBoolean(param,null);
-        if (result != null)
-          setShowScrollbar(result);
-        return true;
-    }
-    return super.setProperty(key, param);
-  }
-
-  @WXComponentProp(name = Constants.Name.SCROLLABLE)
-  public void setScrollable(boolean scrollable) {
-    this.isScrollable = scrollable;
-    WXRecyclerView inner = getHostView().getInnerView();
-    if(inner != null) {
-      inner.setScrollable(scrollable);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.OFFSET_ACCURACY)
-  public void setOffsetAccuracy(int accuracy) {
-    float real = WXViewUtils.getRealPxByWidth(accuracy, getInstance().getInstanceViewPortWidth());
-    this.mOffsetAccuracy = (int) real;
-  }
-
-  @WXComponentProp(name = Constants.Name.DRAGGABLE)
-  public void setDraggable(boolean isDraggable) {
-    if (mDragHelper != null) {
-      mDragHelper.setDraggable(isDraggable);
-    }
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("set draggable : " + isDraggable);
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SHOW_SCROLLBAR)
-  public void setShowScrollbar(boolean show) {
-    if(getHostView() == null || getHostView().getInnerView() == null){
-      return;
-    }
-    if (getOrientation() == Constants.Orientation.VERTICAL) {
-      getHostView().getInnerView().setVerticalScrollBarEnabled(show);
-    } else {
-      getHostView().getInnerView().setHorizontalScrollBarEnabled(show);
-    }
-  }
-
-  @Override
-  public boolean isScrollable() {
-    return isScrollable;
-  }
-
-
-  private void setAppearanceWatch(WXComponent component, int event, boolean enable) {
-    AppearanceHelper item = mAppearComponents.get(component.getRef());
-    if (item != null) {
-      item.setWatchEvent(event, enable);
-    } else if (!enable) {
-      //Do nothing if disable target not exist.
-    } else {
-      WXComponent dChild = findDirectListChild(component);
-      int index = mChildren.indexOf(dChild);
-      if (index != -1) {
-        item = new AppearanceHelper(component, index);
-        item.setWatchEvent(event, true);
-        mAppearComponents.put(component.getRef(), item);
-      }
-    }
-  }
-
-  @Override
-  public void bindAppearEvent(WXComponent component) {
-    setAppearanceWatch(component, AppearanceHelper.APPEAR, true);
-    if(mAppearChangeRunnable == null){
-      mAppearChangeRunnable =  new Runnable() {
-        @Override
-        public void run() {
-          if(mAppearChangeRunnable != null) {
-            notifyAppearStateChange(0, 0, 0, 0);
-          }
-        }
-      };
-    }
-    if (getHostView() != null) {
-      getHostView().removeCallbacks(mAppearChangeRunnable);
-      getHostView().postDelayed(mAppearChangeRunnable, mAppearChangeRunnableDelay);
-    }
-  }
-
-  @Override
-  public void bindDisappearEvent(WXComponent component) {
-    setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, true);
-  }
-
-  @Override
-  public void unbindAppearEvent(WXComponent component) {
-    setAppearanceWatch(component, AppearanceHelper.APPEAR, false);
-  }
-
-  @Override
-  public void unbindDisappearEvent(WXComponent component) {
-    setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, false);
-  }
-
-  @Override
-  public void scrollTo(WXComponent component, Map<String, Object> options) {
-    float offsetFloat = 0;
-    boolean smooth = true;
-
-    if (options != null) {
-      String offsetStr = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
-      smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
-      if (offsetStr != null) {
-        try {
-          offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offsetStr), getInstance().getInstanceViewPortWidth());
-        }catch (Exception e ){
-          WXLogUtils.e("Float parseFloat error :"+e.getMessage());
-        }
-      }
-    }
-
-    final int offset = (int) offsetFloat;
-
-    T bounceRecyclerView = getHostView();
-    if (bounceRecyclerView == null) {
-      return;
-    }
-
-    WXComponent parent = component;
-    WXCell cell = null;
-    while (parent != null) {
-      if (parent instanceof WXCell) {
-        cell = (WXCell) parent;
-        break;
-      }
-      parent = parent.getParent();
-    }
-
-    if (cell != null) {
-      final int pos = mChildren.indexOf(cell);
-      if (pos == -1) {
-        //Invalid position
-        return;
-      }
-      final WXRecyclerView view = bounceRecyclerView.getInnerView();
-      view.scrollTo(smooth, pos, offset, getOrientation());
-    }
-  }
-
-  @Override
-  public void onBeforeScroll(int dx, int dy) {
-    T bounceRecyclerView = getHostView();
-    if (mStickyMap == null || bounceRecyclerView == null) {
-      return;
-    }
-    Map<String, WXComponent> stickyMap = mStickyMap.get(getRef());
-    if (stickyMap == null) {
-      return;
-    }
-    Iterator<Map.Entry<String, WXComponent>> iterator = stickyMap.entrySet().iterator();
-    Map.Entry<String, WXComponent> entry;
-    WXComponent stickyComponent;
-    int currentStickyPos = -1;
-    while (iterator.hasNext()) {
-      entry = iterator.next();
-      stickyComponent = entry.getValue();
-
-      if (stickyComponent != null && stickyComponent instanceof WXCell) {
-
-        WXCell cell = (WXCell) stickyComponent;
-        if (cell.getHostView() == null) {
-          return;
-        }
-
-        int[] location = new int[2];
-        stickyComponent.getHostView().getLocationOnScreen(location);
-        int[] parentLocation = new int[2];
-        stickyComponent.getParentScroller().getView().getLocationOnScreen(parentLocation);
-        int top = location[1] - parentLocation[1];
-
-
-        RecyclerView.LayoutManager layoutManager;
-        boolean beforeFirstVisibleItem = false;
-        boolean removeOldSticky = false;
-        layoutManager = getHostView().getInnerView().getLayoutManager();
-        if (layoutManager instanceof LinearLayoutManager || layoutManager instanceof GridLayoutManager) {
-          int firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
-          int lastVisiblePosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
-          int pos = mChildren.indexOf(cell);
-          cell.setScrollPositon(pos);
-          if (pos <= firstVisiblePosition
-                  || (cell.getStickyOffset() > 0 && firstVisiblePosition < pos && pos <= lastVisiblePosition  &&
-                  top <= cell.getStickyOffset())) {
-            beforeFirstVisibleItem = true;
-            if(pos > currentStickyPos) {
-              currentStickyPos = pos;
-            }
-          }else{
-            removeOldSticky = true;
-          }
-        } else if(layoutManager instanceof StaggeredGridLayoutManager){
-          int [] firstItems= new int[3];
-          int firstVisiblePosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(firstItems)[0];
-          int lastVisiblePosition = ((StaggeredGridLayoutManager)  layoutManager).findLastVisibleItemPositions(firstItems)[0];
-          int pos = mChildren.indexOf(cell);
-
-          if (pos <= firstVisiblePosition || (cell.getStickyOffset() > 0 && firstVisiblePosition < pos && pos <= lastVisiblePosition  &&
-                  top <= cell.getStickyOffset())) {
-            beforeFirstVisibleItem = true;
-            if(pos > currentStickyPos) {
-              currentStickyPos = pos;
-            }
-          }else{
-            removeOldSticky = true;
-          }
-        }
-
-
-        boolean showSticky = beforeFirstVisibleItem && cell.getLocationFromStart() >= 0 && top <= cell.getStickyOffset() && dy >= 0;
-        boolean removeSticky = cell.getLocationFromStart() <= cell.getStickyOffset() && top > cell.getStickyOffset() && dy <= 0;
-        if (showSticky) {
-          bounceRecyclerView.notifyStickyShow(cell);
-        } else if (removeSticky || removeOldSticky) {
-          bounceRecyclerView.notifyStickyRemove(cell);
-        }
-        cell.setLocationFromStart(top);
-      }
-    }
-
-    if(currentStickyPos >= 0){
-      bounceRecyclerView.updateStickyView(currentStickyPos);
-    }else{
-      if(bounceRecyclerView instanceof BounceRecyclerView){
-        ((BounceRecyclerView) bounceRecyclerView).getStickyHeaderHelper().clearStickyHeaders();
-      }
-    }
-  }
-
-  @Override
-  public int getScrollY() {
-    T bounceRecyclerView = getHostView();
-    return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollY();
-  }
-
-  @Override
-  public int getScrollX() {
-    T bounceRecyclerView = getHostView();
-    return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollX();
-  }
-
-  /**
-   * Append a child component to the end of list. This will not refresh the underlying
-   * view immediately. The message of index of the inserted child is given to the adapter, and the
-   * adapter will determine when to refresh. The default implementation of adapter will push the
-   * message into a message and refresh the view in a period of time.
-   *
-   * @param child the inserted child
-   */
-  @Override
-  public void addChild(WXComponent child) {
-    addChild(child, -1);
-  }
-
-  @Override
-  protected int getChildrenLayoutTopOffset() {
-    return 0;
-  }
-
-  /**
-   * @param child the inserted child
-   * @param index the index of the child to be inserted.
-   * @see #addChild(WXComponent)
-   */
-  @Override
-  public void addChild(WXComponent child, int index) {
-    super.addChild(child, index);
-    if (child == null || index < -1) {
-      return;
-    }
-    int count = mChildren.size();
-    index = index >= count ? -1 : index;
-    bindViewType(child);
-
-    int adapterPosition = index == -1 ? mChildren.size() - 1 : index;
-    final T view = getHostView();
-    if (view != null) {
-      boolean isAddAnimation = false;
-      if (getBasicComponentData() != null) {
-        Object attr = getAttrs().get(Constants.Name.INSERT_CELL_ANIMATION);
-        if (Constants.Value.DEFAULT.equals(attr)) {
-          isAddAnimation = true;
-        }
-      }
-      if (isAddAnimation) {
-        view.getInnerView().setItemAnimator(mItemAnimator);
-      } else {
-        view.getInnerView().setItemAnimator(null);
-      }
-      boolean isKeepScrollPosition =  false;
-      if (child.getBasicComponentData() != null) {
-        Object attr = child.getAttrs().get(Constants.Name.KEEP_SCROLL_POSITION);
-        if (WXUtils.getBoolean(attr, false) && index <= getChildCount() && index>-1) {
-          isKeepScrollPosition = true;
-        }
-      }
-      if (isKeepScrollPosition) {
-        if(view.getInnerView().getLayoutManager() instanceof  LinearLayoutManager){
-          if(keepPositionCell == null){
-            int last=((LinearLayoutManager)view.getInnerView().getLayoutManager()).findLastCompletelyVisibleItemPosition();
-            ListBaseViewHolder holder = (ListBaseViewHolder) view.getInnerView().findViewHolderForAdapterPosition(last);
-            if(holder != null){
-              keepPositionCell = holder.getComponent();
-            }
-            if(keepPositionCell != null) {
-              if(!view.getInnerView().isLayoutFrozen()){ //frozen, prevent layout when scroll
-                view.getInnerView().setLayoutFrozen(true);
-              }
-              if(keepPositionCellRunnable != null){
-                view.removeCallbacks(keepPositionCellRunnable);
-              }
-              keepPositionCellRunnable = new Runnable() {
-                @Override
-                public void run() {
-                  if(keepPositionCell != null){
-                    int keepPosition = indexOf(keepPositionCell);
-                    int offset = 0;
-                    if(keepPositionCell.getHostView() != null){
-                      offset = keepPositionCell.getHostView().getTop();
-                    }
-                    if(offset > 0) {
-                      ((LinearLayoutManager) view.getInnerView().getLayoutManager()).scrollToPositionWithOffset(keepPosition, offset);
-                    }else{
-                      view.getInnerView().getLayoutManager().scrollToPosition(keepPosition);
-
-                    }
-                    view.getInnerView().setLayoutFrozen(false);
-                    keepPositionCell = null;
-                    keepPositionCellRunnable = null;
-                  }
-                }
-              };
-            }
-          }
-          if(keepPositionCellRunnable == null){
-            view.getInnerView().scrollToPosition(((LinearLayoutManager)view.getInnerView().getLayoutManager()).findLastVisibleItemPosition());
-          }
-        }
-        view.getRecyclerViewBaseAdapter().notifyItemInserted(adapterPosition);
-        if(keepPositionCellRunnable != null){
-          view.removeCallbacks(keepPositionCellRunnable);
-          view.postDelayed(keepPositionCellRunnable, keepPositionLayoutDelay);
-        }
-      } else {
-        view.getRecyclerViewBaseAdapter().notifyItemChanged(adapterPosition);
-      }
-    }
-    relocateAppearanceHelper();
-  }
-
-  private void relocateAppearanceHelper() {
-    Iterator<Map.Entry<String, AppearanceHelper>> iterator = mAppearComponents.entrySet().iterator();
-    while (iterator.hasNext()) {
-      Map.Entry<String, AppearanceHelper> item = iterator.next();
-      AppearanceHelper value = item.getValue();
-      WXComponent dChild = findDirectListChild(value.getAwareChild());
-      int index = mChildren.indexOf(dChild);
-      value.setCellPosition(index);
-    }
-  }
-
-
-  /**
-   * RecyclerView manage its children in a way that different from {@link WXVContainer}. Therefore,
-   * {@link WXVContainer#addSubView(View, int)} is an empty implementation in {@link
-   * com.taobao.weex.ui.view.listview.WXRecyclerView}
-   */
-  @Override
-  public void addSubView(View child, int index) {
-
-  }
-
-  /**
-   * Remove the child from list. This method will use {@link
-   * java.util.List#indexOf(Object)} to retrieve the component to be deleted. Like {@link
-   * #addChild(WXComponent)}, this method will not refresh the view immediately, the adapter will
-   * decide when to refresh.
-   *
-   * @param child the child to be removed
-   */
-  @Override
-  public void remove(WXComponent child, boolean destroy) {
-    int index = mChildren.indexOf(child);
-    if (destroy) {
-      child.detachViewAndClearPreInfo();
-    }
-    unBindViewType(child);
-
-    T view = getHostView();
-    if (view == null) {
-      return;
-    }
-
-    boolean isRemoveAnimation = false;
-    Object attr = child.getAttrs().get(Constants.Name.DELETE_CELL_ANIMATION);
-    if (Constants.Value.DEFAULT.equals(attr)) {
-      isRemoveAnimation = true;
-    }
-    if (isRemoveAnimation) {
-      view.getInnerView().setItemAnimator(mItemAnimator);
-    } else {
-      view.getInnerView().setItemAnimator(null);
-    }
-
-    view.getRecyclerViewBaseAdapter().notifyItemRemoved(index);
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d(TAG, "removeChild child at " + index);
-    }
-    super.remove(child, destroy);
-  }
-
-
-
-  @Override
-  public void computeVisiblePointInViewCoordinate(PointF pointF) {
-    RecyclerView view = getHostView().getInnerView();
-    pointF.set(view.computeHorizontalScrollOffset(), view.computeVerticalScrollOffset());
-  }
-
-  /**
-   * Recycle viewHolder and its underlying view. This may because the view is removed or reused.
-   * Either case, this method will be called.
-   *
-   * @param holder The view holder to be recycled.
-   */
-  @Override
-  public void onViewRecycled(ListBaseViewHolder holder) {
-    long begin = System.currentTimeMillis();
-
-    holder.setComponentUsing(false);
-    if (holder != null
-            && holder.canRecycled()
-            && holder.getComponent() != null
-            && !holder.getComponent().isUsing()) {
-      holder.recycled();
-
-    } else {
-      WXLogUtils.w(TAG, "this holder can not be allowed to  recycled");
-    }
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d(TAG, "Recycle holder " + (System.currentTimeMillis() - begin) + "  Thread:" + Thread.currentThread().getName());
-    }
-  }
-
-  /**
-   * Bind the component of the position to the holder. Then flush the view.
-   *
-   * @param holder   viewHolder, which holds reference to the view
-   * @param position position of component in list
-   */
-  @Override
-  public void onBindViewHolder(final ListBaseViewHolder holder, int position) {
-    if (holder == null) return;
-    holder.setComponentUsing(true);
-    WXComponent component = getChild(position);
-    if (component == null
-            || (component instanceof WXRefresh)
-            || (component instanceof WXLoading)
-            || (component.isFixed())
-            ) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d(TAG, "Bind WXRefresh & WXLoading " + holder);
-      }
-      if(component instanceof  WXBaseRefresh
-              && holder.getView() != null
-              && (component.getAttrs().get("holderBackground") != null)){
-        Object holderBackground = component.getAttrs().get("holderBackground");
-        int color = WXResourceUtils.getColor(holderBackground.toString(), Color.WHITE);
-        holder.getView().setBackgroundColor(color);
-        holder.getView().setVisibility(View.VISIBLE);
-        holder.getView().postInvalidate();
-      }
-      return;
-    }
-
-    if (holder.getComponent() != null && holder.getComponent() instanceof WXCell) {
-      if(holder.isRecycled()) {
-        holder.bindData(component);
-        component.onRenderFinish(STATE_UI_FINISH);
-      }
-      if (mDragHelper == null || !mDragHelper.isDraggable()) {
-        return;
-      }
-      mTriggerType = (mTriggerType == null) ? DEFAULT_TRIGGER_TYPE : mTriggerType;
-
-      WXCell cell = (WXCell) holder.getComponent();
-      boolean isExcluded = DEFAULT_EXCLUDED;
-      WXAttr cellAttrs = cell.getAttrs();
-      isExcluded = WXUtils.getBoolean(cellAttrs.get(EXCLUDED), DEFAULT_EXCLUDED);
-
-      mDragHelper.setDragExcluded(holder, isExcluded);
-
-      //NOTICE: event maybe consumed by other views
-      if (DragTriggerType.PAN.equals(mTriggerType)) {
-        mDragHelper.setLongPressDragEnabled(false);
-
-        WXComponent anchorComponent = findComponentByAnchorName(cell, DRAG_ANCHOR);
-
-        if (anchorComponent != null && anchorComponent.getHostView() != null && !isExcluded) {
-          View anchor = anchorComponent.getHostView();
-          anchor.setOnTouchListener(new View.OnTouchListener() {
-            @SuppressLint("ClickableViewAccessibility")
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-              if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
-                mDragHelper.startDrag(holder);
-              }
-              return true;
-            }
-          });
-        } else {
-          if (WXEnvironment.isApkDebugable()) {
-            if(!isExcluded) {
-              WXLogUtils.e(TAG, "[error] onBindViewHolder: the anchor component or view is not found");
-            } else {
-              WXLogUtils.d(TAG, "onBindViewHolder: position "+ position + " is drag excluded");
-            }
-          }
-        }
-
-      } else if (DragTriggerType.LONG_PRESS.equals(mTriggerType)) {
-        mDragHelper.setLongPressDragEnabled(true);
-      }
-    }
-
-  }
-
-  protected void markComponentUsable(){
-    for (WXComponent component : mChildren){
-      component.setUsing(false);
-    }
-  }
-  /**
-   * Create an instance of {@link ListBaseViewHolder} for the given viewType (not for the given
-   * index). This  markComponentUsable();method will look up for the first component that fits the viewType requirement and
-   * doesn't be used. Then create the certain type of view, detach the view f[rom the component.
-   *
-   * @param parent   the ViewGroup into which the new view will be inserted
-   * @param viewType the type of the new view
-   * @return the created view holder.
-   */
-  @Override
-  public ListBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-    if (mChildren != null) {
-      if (mViewTypes == null)
-        return createVHForFakeComponent(viewType);
-      ArrayList<WXComponent> mTypes = mViewTypes.get(viewType);
-      checkRecycledViewPool(viewType);
-      if (mTypes == null)
-        return createVHForFakeComponent(viewType);
-
-      for (int i = 0; i < mTypes.size(); i++) {
-        WXComponent component = mTypes.get(i);
-        if (component == null
-            || component.isUsing()) {
-          continue;
-        }
-        if (component.isFixed()) {
-          return createVHForFakeComponent(viewType);
-        } else {
-          if (component instanceof WXCell) {
-            if (component.getRealView() != null) {
-              return new ListBaseViewHolder(component, viewType);
-            } else {
-              component.lazy(false);
-              component.createView();
-              component.applyLayoutAndEvent(component);
-              return new ListBaseViewHolder(component, viewType, true);
-            }
-          } else if (component instanceof WXBaseRefresh) {
-            return createVHForRefreshComponent(viewType);
-          } else {
-            WXLogUtils.e(TAG, "List cannot include element except cell、header、fixed、refresh and loading");
-            return createVHForFakeComponent(viewType);
-          }
-        }
-      }
-    }
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.e(TAG, "Cannot find request viewType: " + viewType);
-    }
-    return createVHForFakeComponent(viewType);
-  }
-
-  /**
-   * Forbid ViewHolder cache if viewType > MAX_VIEWTYPE_ALLOW_CACHE
-   *
-   * @param viewType
-   */
-  private void checkRecycledViewPool(int viewType) {
-    try {
-      if (mViewTypes.size() > MAX_VIEWTYPE_ALLOW_CACHE)
-        mAllowCacheViewHolder = false;
-
-      if (mDownForBidCacheViewHolder)
-        if (getHostView() != null && getHostView().getInnerView() != null)
-          getHostView().getInnerView().getRecycledViewPool().setMaxRecycledViews(viewType, 0);
-
-      if (!mDownForBidCacheViewHolder) {
-        if (!mAllowCacheViewHolder) {
-          if (getHostView() != null && getHostView().getInnerView() != null) {
-            for (int i = 0; i < mViewTypes.size(); i++) {
-              getHostView().getInnerView().getRecycledViewPool().setMaxRecycledViews(mViewTypes.keyAt(i), 0);
-            }
-            mDownForBidCacheViewHolder = true;
-          }
-        }
-      }
-    } catch (Exception e) {
-      WXLogUtils.e(TAG, "Clear recycledViewPool error!");
-    }
-  }
-
-  /**
-   * Return the child component type. The type is defined by scopeValue in .we file.
-   *
-   * @param position the position of the child component.
-   * @return the type of certain component.
-   */
-  @Override
-  public int getItemViewType(int position) {
-    return generateViewType(getChild(position));
-  }
-
-  @Nullable
-  private WXComponent findComponentByAnchorName(@NonNull WXComponent root, @NonNull String anchorName) {
-    long start = 0;
-    if (WXEnvironment.isApkDebugable()) {
-      start = System.currentTimeMillis();
-    }
-
-    Deque<WXComponent> deque = new ArrayDeque<>();
-    deque.add(root);
-    while (!deque.isEmpty()) {
-      WXComponent curComponent = deque.removeFirst();
-      if (curComponent != null) {
-        String isAnchorSet = WXUtils.getString(curComponent.getAttrs().get(anchorName), null);
-
-        //hit
-        if (isAnchorSet != null && isAnchorSet.equals("true")) {
-          if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.d("dragPerf", "findComponentByAnchorName time: " + (System.currentTimeMillis() - start) + "ms");
-          }
-          return curComponent;
-        }
-      }
-      if (curComponent instanceof WXVContainer) {
-        WXVContainer container = (WXVContainer) curComponent;
-        for (int i = 0, len = container.childCount(); i < len; i++) {
-          WXComponent child = container.getChild(i);
-          deque.add(child);
-        }
-      }
-    }
-
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("dragPerf", "findComponentByAnchorName elapsed time: " + (System.currentTimeMillis() - start) + "ms");
-    }
-    return null;
-
-  }
-
-  private String getTriggerType(@Nullable WXComponent component) {
-    String triggerType = DEFAULT_TRIGGER_TYPE;
-    if (component == null) {
-      return triggerType;
-    }
-    triggerType = WXUtils.getString(component.getAttrs().get(DRAG_TRIGGER_TYPE), DEFAULT_TRIGGER_TYPE);
-    if (!DragTriggerType.LONG_PRESS.equals(triggerType) && !DragTriggerType.PAN.equals(triggerType)) {
-      triggerType = DEFAULT_TRIGGER_TYPE;
-    }
-
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d(TAG, "trigger type is " + triggerType);
-    }
-
-    return triggerType;
-  }
-
-
-  /**
-   * ViewType will be classified into {HashMap<Integer,ArrayList<Integer>> mViewTypes}
-   *
-   * @param component
-   */
-  private void bindViewType(WXComponent component) {
-    int id = generateViewType(component);
-
-    if (mViewTypes == null) {
-      mViewTypes = new SparseArray<>();
-    }
-
-    ArrayList<WXComponent> mTypes = mViewTypes.get(id);
-
-    if (mTypes == null) {
-      mTypes = new ArrayList<>();
-      mViewTypes.put(id, mTypes);
-    }
-    mTypes.add(component);
-  }
-
-  private void unBindViewType(WXComponent component) {
-    int id = generateViewType(component);
-
-    if (mViewTypes == null)
-      return;
-    ArrayList<WXComponent> mTypes = mViewTypes.get(id);
-    if (mTypes == null)
-      return;
-
-    mTypes.remove(component);
-  }
-
-  /**
-   * generate viewtype by component
-   *
-   * @param component
-   * @return
-   */
-  private int generateViewType(WXComponent component) {
-    long id;
-    try {
-      id = Integer.parseInt(component.getRef());
-      String type = component.getAttrs().getScope();
-
-      if (!TextUtils.isEmpty(type)) {
-        if (mRefToViewType == null) {
-          mRefToViewType = new ArrayMap<>();
-        }
-        if (!mRefToViewType.containsKey(type)) {
-          mRefToViewType.put(type, id);
-        }
-        id = mRefToViewType.get(type);
-
-      }
-    } catch (RuntimeException e) {
-      WXLogUtils.eTag(TAG, e);
-      id = RecyclerView.NO_ID;
-      WXLogUtils.e(TAG, "getItemViewType: NO ID, this will crash the whole render system of WXListRecyclerView");
-    }
-    return (int) id;
-  }
-
-  /**
-   * Get child component num.
-   *
-   * @return return the size of {@link #mChildren} if mChildren is not empty, otherwise, return 0;
-   */
-  @Override
-  public int getItemCount() {
-    return getChildCount();
-  }
-
-  @Override
-  public boolean onFailedToRecycleView(ListBaseViewHolder holder) {
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d(TAG, "Failed to recycle " + holder);
-    }
-    return false;
-  }
-
-  @Override
-  public long getItemId(int position) {
-    long id;
-    try {
-      id = Long.parseLong(getChild(position).getRef());
-    } catch (RuntimeException e) {
-      WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
-      id = RecyclerView.NO_ID;
-    }
-    return id;
-  }
-
-  @Override
-  public void onLoadMore(int offScreenY) {
-    try {
-      String offset = getAttrs().getLoadMoreOffset();
-
-      if (TextUtils.isEmpty(offset)) {
-        offset = "0";
-      }
-
-
-      float offsetParsed = WXViewUtils.getRealPxByWidth(WXUtils.getInt(offset),getInstance().getInstanceViewPortWidth());
-
-      if (offScreenY <= offsetParsed && getEvents().contains(Constants.Event.LOADMORE)) {
-        if (mListCellCount != mChildren.size()
-            || mForceLoadmoreNextTime) {
-          fireEvent(Constants.Event.LOADMORE);
-          mListCellCount = mChildren.size();
-          mForceLoadmoreNextTime = false;
-        }
-      }
-    } catch (Exception e) {
-      WXLogUtils.d(TAG + "onLoadMore :", e);
-    }
-  }
-
-  @Override
-  public void notifyAppearStateChange(int firstVisible, int lastVisible, int directionX, int directionY) {
-    if(mAppearChangeRunnable != null) {
-      getHostView().removeCallbacks(mAppearChangeRunnable);
-      mAppearChangeRunnable = null;
-    }
-    //notify appear state
-    Iterator<AppearanceHelper> it = mAppearComponents.values().iterator();
-    String direction = directionY > 0 ? Constants.Value.DIRECTION_UP :
-            directionY < 0 ? Constants.Value.DIRECTION_DOWN : null;
-    if (getOrientation() == Constants.Orientation.HORIZONTAL && directionX != 0) {
-      direction = directionX > 0 ? Constants.Value.DIRECTION_LEFT : Constants.Value.DIRECTION_RIGHT;
-    }
-
-    while (it.hasNext()) {
-      AppearanceHelper item = it.next();
-      WXComponent component = item.getAwareChild();
-
-      if (!item.isWatch()) {
-        continue;
-      }
-
-
-      View view = component.getHostView();
-      if (view == null) {
-        continue;
-      }
-
-      boolean outOfVisibleRange = !ViewCompat.isAttachedToWindow(view);
-      boolean visible = (!outOfVisibleRange) && item.isViewVisible(true);
-
-      int result = item.setAppearStatus(visible);
-      if (result == AppearanceHelper.RESULT_NO_CHANGE) {
-        continue;
-      }
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d("appear", "item " + item.getCellPositionINScollable() + " result " + result);
-      }
-      component.notifyAppearStateChange(result == AppearanceHelper.RESULT_APPEAR ? Constants.Event.APPEAR : Constants.Event.DISAPPEAR, direction);
-    }
-  }
-
-  @NonNull
-  private ListBaseViewHolder createVHForFakeComponent(int viewType) {
-    FrameLayout view = new FrameLayout(getContext());
-    view.setBackgroundColor(Color.WHITE);
-    view.setLayoutParams(new FrameLayout.LayoutParams(0, 0));
-    return new ListBaseViewHolder(view, viewType);
-  }
-
-
-  private ListBaseViewHolder createVHForRefreshComponent(int viewType) {
-    FrameLayout view = new FrameLayout(getContext());
-    view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
-    return new ListBaseViewHolder(view, viewType);
-  }
-
-  @JSMethod
-  public void resetLoadmore() {
-    mForceLoadmoreNextTime = true;
-    mListCellCount = 0;
-  }
-
-  @Override
-  public void addEvent(String type) {
-    super.addEvent(type);
-    if (ScrollStartEndHelper.isScrollEvent(type)
-            && getHostView() != null
-            && getHostView().getInnerView() != null
-            && !mHasAddScrollEvent) {
-      mHasAddScrollEvent = true;
-      WXRecyclerView innerView = getHostView().getInnerView();
-      innerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-        private int offsetXCorrection, offsetYCorrection;
-        private boolean mFirstEvent = true;
-
-        @Override
-        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-          super.onScrolled(recyclerView, dx, dy);
-//          WXLogUtils.e("SCROLL", dx + ", " + dy + ", " + recyclerView.computeHorizontalScrollRange()
-//          + ", " + recyclerView.computeVerticalScrollRange()
-//          + ", " + recyclerView.computeHorizontalScrollOffset()
-//          + ", " + recyclerView.computeVerticalScrollOffset());
-
-          int offsetX = recyclerView.computeHorizontalScrollOffset();
-          int offsetY = recyclerView.computeVerticalScrollOffset();
-
-          if (dx == 0 && dy == 0) {
-            offsetXCorrection = offsetX;
-            offsetYCorrection = offsetY;
-            offsetX = 0;
-            offsetY = 0;
-          } else {
-            offsetX = offsetX - offsetXCorrection;
-            offsetY = offsetY - offsetYCorrection;
-          }
-          getScrollStartEndHelper().onScrolled(offsetX, offsetY);
-          if(!getEvents().contains(Constants.Event.SCROLL)){
-            return;
-          }
-          if (mFirstEvent) {
-            //skip first event
-            mFirstEvent = false;
-            return;
-          }
-
-          RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-          if (!layoutManager.canScrollVertically()) {
-            return;
-          }
-
-          if (shouldReport(offsetX, offsetY)) {
-            fireScrollEvent(recyclerView, offsetX, offsetY);
-          }
-        }
-      });
-    }
-  }
-
-  private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY) {
-    fireEvent(Constants.Event.SCROLL, getScrollEvent(recyclerView, offsetX, offsetY));
-  }
-
-  public Map<String, Object> getScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY){
-    if(getOrientation() == Constants.Orientation.VERTICAL){
-      offsetY = - calcContentOffset(recyclerView);
-    }
-    int contentWidth = recyclerView.getMeasuredWidth() + recyclerView.computeHorizontalScrollRange();
-    int contentHeight = 0;
-    for (int i = 0; i < getChildCount(); i++) {
-      WXComponent child = getChild(i);
-      if (child != null) {
-        contentHeight += child.getLayoutHeight();
-      }
-    }
-
-    Map<String, Object> event = new HashMap<>(3);
-    Map<String, Object> contentSize = new HashMap<>(3);
-    Map<String, Object> contentOffset = new HashMap<>(3);
-
-    contentSize.put(Constants.Name.WIDTH, WXViewUtils.getWebPxByWidth(contentWidth, getInstance().getInstanceViewPortWidth()));
-    contentSize.put(Constants.Name.HEIGHT, WXViewUtils.getWebPxByWidth(contentHeight, getInstance().getInstanceViewPortWidth()));
-
-    contentOffset.put(Constants.Name.X, - WXViewUtils.getWebPxByWidth(offsetX, getInstance().getInstanceViewPortWidth()));
-    contentOffset.put(Constants.Name.Y, - WXViewUtils.getWebPxByWidth(offsetY, getInstance().getInstanceViewPortWidth()));
-    event.put(Constants.Name.CONTENT_SIZE, contentSize);
-    event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
-    event.put(Constants.Name.ISDRAGGING, recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING);
-    return event;
-  }
-
-  private boolean shouldReport(int offsetX, int offsetY) {
-    if (mLastReport.x == -1 && mLastReport.y == -1) {
-      mLastReport.x = offsetX;
-      mLastReport.y = offsetY;
-      return true;
-    }
-
-    int gapX = Math.abs(mLastReport.x - offsetX);
-    int gapY = Math.abs(mLastReport.y - offsetY);
-
-    if (gapX >= mOffsetAccuracy || gapY >= mOffsetAccuracy) {
-      mLastReport.x = offsetX;
-      mLastReport.y = offsetY;
-      return true;
-    }
-
-    return false;
-  }
-
-
-
-  public int calcContentOffset(RecyclerView recyclerView) {
-    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-    if (layoutManager instanceof LinearLayoutManager) {
-      int firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
-      if (firstVisibleItemPosition == -1) {
-        return 0;
-      }
-
-      View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
-      int firstVisibleViewOffset = 0;
-      if (firstVisibleView != null) {
-        firstVisibleViewOffset = firstVisibleView.getTop();
-      }
-
-      int offset = 0;
-      for (int i=0;i<firstVisibleItemPosition;i++) {
-        WXComponent child = getChild(i);
-        if (child != null) {
-          offset -= child.getLayoutHeight();
-        }
-      }
-
-      if (layoutManager instanceof GridLayoutManager) {
-        int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
-        offset = offset / spanCount;
-      }
-
-      offset += firstVisibleViewOffset;
-      return offset;
-    } else if (layoutManager instanceof StaggeredGridLayoutManager) {
-      int spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
-      int firstVisibleItemPosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(null)[0];
-      if (firstVisibleItemPosition == -1) {
-        return 0;
-      }
-
-      View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
-      int firstVisibleViewOffset = 0;
-      if (firstVisibleView != null) {
-        firstVisibleViewOffset = firstVisibleView.getTop();
-      }
-
-      int offset = 0;
-      for (int i=0;i<firstVisibleItemPosition;i++) {
-        WXComponent child = getChild(i);
-        if (child != null) {
-          offset -= child.getLayoutHeight();
-        }
-      }
-
-      offset = offset / spanCount;
-      offset += firstVisibleViewOffset;
-      return offset;
-    }
-    //Unhandled LayoutManager type
-    return -1;
-  }
-
-  public ScrollStartEndHelper getScrollStartEndHelper() {
-    if(mScrollStartEndHelper == null){
-      mScrollStartEndHelper = new ScrollStartEndHelper(this);
-    }
-    return mScrollStartEndHelper;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DefaultDragHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DefaultDragHelper.java
deleted file mode 100644
index 50c4bb7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DefaultDragHelper.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Description:
- * Drag-drop support for list
- * <p>
- * Created by rowandjj(chuyi)<br/>
- */
-
-class DefaultDragHelper implements DragHelper {
-
-    private boolean mLongPressEnabled;
-
-    @NonNull
-    private final EventTrigger mEventTrigger;
-    @NonNull
-    private final RecyclerView mRecyclerView;
-    @NonNull
-    private final List<WXComponent> mDataSource;
-    @NonNull
-    private ItemTouchHelper mItemTouchHelper;
-
-    private static final String EVENT_START_DRAG = "dragstart";
-    private static final String EVENT_END_DRAG = "dragend";
-
-    private static final String TAG_EXCLUDED = "drag_excluded";
-
-    private static final String TAG = "WXListExComponent";
-
-    private boolean isDraggable = false;
-
-    DefaultDragHelper(@NonNull List<WXComponent> dataSource, @NonNull RecyclerView recyclerView, @NonNull EventTrigger trigger) {
-        this.mDataSource = dataSource;
-        this.mEventTrigger = trigger;
-        this.mRecyclerView = recyclerView;
-
-        //attach
-        this.mItemTouchHelper = new ItemTouchHelper(new DragSupportCallback(this, true));
-        try {
-            mItemTouchHelper.attachToRecyclerView(mRecyclerView);
-        }catch (Throwable e) {
-            //ignore
-        }
-    }
-
-    @Override
-    public void onDragStart(@NonNull WXComponent component, int from) {
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.d(TAG, "list on drag start : from index " + from);
-        }
-        mEventTrigger.triggerEvent(EVENT_START_DRAG, buildEvent(component.getRef(), from, -1));
-    }
-
-    @Override
-    public void onDragEnd(@NonNull WXComponent component, int from, int to) {
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.d(TAG, "list on drag end : " + "from index " + from + " to index " + to);
-        }
-        mEventTrigger.triggerEvent(EVENT_END_DRAG, buildEvent(component.getRef(), from, to));
-    }
-
-    @Override
-    public void onDragging(int fromPos, int toPos) {
-        if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.d(TAG, "list on dragging : from index " + fromPos + " to index " + toPos);
-        }
-
-        RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
-        if (adapter == null) {
-            WXLogUtils.e(TAG, "drag failed because of RecyclerView#Adapter is not bound");
-            return;
-        }
-
-        if (fromPos >= 0 && fromPos <= mDataSource.size() - 1 && toPos >= 0 && toPos <= mDataSource.size() - 1) {
-            Collections.swap(mDataSource, fromPos, toPos);
-            adapter.notifyItemMoved(fromPos, toPos);
-        }
-    }
-
-    @Override
-    public boolean isLongPressDragEnabled() {
-        return mLongPressEnabled;
-    }
-
-    @Override
-    public void setLongPressDragEnabled(boolean enabled) {
-        this.mLongPressEnabled = enabled;
-    }
-
-    @Override
-    public void startDrag(@NonNull RecyclerView.ViewHolder viewHolder) {
-        if (isDraggable) {
-            mItemTouchHelper.startDrag(viewHolder);
-        }
-    }
-
-    @Override
-    public boolean isDraggable() {
-        return this.isDraggable;
-    }
-
-    @Override
-    public void setDraggable(boolean draggable) {
-        this.isDraggable = draggable;
-    }
-
-    @Override
-    public void setDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder, boolean isExcluded) {
-        if (viewHolder.itemView == null) {
-            if (WXEnvironment.isApkDebugable()) {
-                WXLogUtils.e(TAG, "[error] viewHolder.itemView is null");
-            }
-            return;
-        }
-        if (isExcluded) {
-            viewHolder.itemView.setTag(TAG_EXCLUDED);
-        } else {
-            viewHolder.itemView.setTag(null);
-        }
-    }
-
-    @Override
-    public boolean isDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder) {
-        if (viewHolder.itemView == null) {
-            if (WXEnvironment.isApkDebugable()) {
-                WXLogUtils.e(TAG, "[error] viewHolder.itemView is null");
-            }
-            return false;
-        }
-        return viewHolder.itemView.getTag() != null && TAG_EXCLUDED.equals(viewHolder.itemView.getTag());
-    }
-
-    private Map<String, Object> buildEvent(@Nullable String target, int fromIndex, int toIndex) {
-        Map<String, Object> args = new HashMap<>(4);
-        args.put("target", target == null ? "unknown" : target);
-        args.put("fromIndex", fromIndex);
-        args.put("toIndex", toIndex);
-        args.put("timestamp", System.currentTimeMillis());
-        return args;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DragHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DragHelper.java
deleted file mode 100644
index ea66feb..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DragHelper.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Description:
- *
- * interface for drag&drop support
- *
- * <p>
- * Created by rowandjj(chuyi)<br/>
- * Date: 16/4/5<br/>
- * Time: 上午11:34<br/>
- */
-interface DragHelper {
-
-    void onDragStart(@NonNull WXComponent component, int from);
-
-    void onDragEnd(@NonNull WXComponent component, int from, int to);
-
-    void onDragging(int fromPos, int toPos);
-
-    boolean isLongPressDragEnabled();
-
-    void setLongPressDragEnabled(boolean enabled);
-
-    void startDrag(@NonNull RecyclerView.ViewHolder viewHolder);
-
-    boolean isDraggable();
-
-    void setDraggable(boolean draggable);
-
-    void setDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder, boolean isExcluded);
-
-    boolean isDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DragSupportCallback.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DragSupportCallback.java
deleted file mode 100644
index 9b82517..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/DragSupportCallback.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.support.annotation.NonNull;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.support.v7.widget.helper.ItemTouchHelper;
-
-import com.taobao.weex.ui.view.listview.adapter.ListBaseViewHolder;
-import com.taobao.weex.utils.WXLogUtils;
-
-/**
- * Description:
- * An implementation of {@link ItemTouchHelper.Callback}. with drag&drop support:)
- *
- * <p>
- * Created by rowandjj(chuyi)<br/>
- * Date: 17/4/22<br/>
- * Time: 上午11:25<br/>
- */
-class DragSupportCallback extends ItemTouchHelper.Callback {
-    private final DragHelper mDragHelper;
-    private boolean mEnableDifferentViewTypeDrag = false;
-
-    private int dragFrom = -1;
-    private int dragTo = -1;
-
-    private static final String TAG = "WXListExComponent";
-
-    DragSupportCallback(@NonNull DragHelper DragHelper) {
-        this.mDragHelper = DragHelper;
-        this.mEnableDifferentViewTypeDrag = false;
-    }
-
-    DragSupportCallback(@NonNull DragHelper DragHelper, boolean enableDifferentViewTypeDrag) {
-        this.mDragHelper = DragHelper;
-        this.mEnableDifferentViewTypeDrag = enableDifferentViewTypeDrag;
-    }
-
-    @Override
-    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
-        if (recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
-            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
-            int swipeFlags = 0;
-            return makeMovementFlags(dragFlags, swipeFlags);
-        } else {
-            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
-            int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
-            return makeMovementFlags(dragFlags, swipeFlags);
-        }
-    }
-
-    @Override
-    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
-        if (viewHolder == null || target == null) {
-            return false;
-        }
-
-        if (!mEnableDifferentViewTypeDrag && viewHolder.getItemViewType() != target.getItemViewType()) {
-            return false;
-        }
-
-        if (mDragHelper.isDragExcluded(viewHolder)) {
-            return false;
-        }
-
-        try {
-            int fromPos = viewHolder.getAdapterPosition();
-            int toPos = target.getAdapterPosition();
-
-            if (dragFrom == -1) {
-                dragFrom = fromPos;
-            }
-            dragTo = toPos;
-
-            mDragHelper.onDragging(fromPos, toPos);
-            return true;
-        } catch (Exception e) {
-            WXLogUtils.e(TAG, e.getMessage());
-            return false;
-        }
-    }
-
-
-    @Override
-    public boolean isLongPressDragEnabled() {
-        return mDragHelper.isDraggable() && mDragHelper.isLongPressDragEnabled();
-    }
-
-    @Override
-    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
-    }
-
-    @Override
-    public boolean isItemViewSwipeEnabled() {
-        return false;
-    }
-
-    @Override
-    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
-        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && viewHolder instanceof ListBaseViewHolder) {
-            ListBaseViewHolder vh = (ListBaseViewHolder) viewHolder;
-            if (vh.getComponent() != null) {
-                mDragHelper.onDragStart(vh.getComponent(), vh.getAdapterPosition());
-            }
-        }
-
-        super.onSelectedChanged(viewHolder, actionState);
-    }
-
-
-    @Override
-    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
-        super.clearView(recyclerView, viewHolder);
-
-        if (viewHolder instanceof ListBaseViewHolder) {
-            ListBaseViewHolder vh = (ListBaseViewHolder) viewHolder;
-            if (vh.getComponent() != null) {
-                if (dragFrom != -1 && dragTo != -1) {
-                    mDragHelper.onDragEnd(vh.getComponent(), dragFrom, dragTo);
-                }
-            }
-
-        }
-
-        dragFrom = dragTo = -1;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/EventTrigger.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/EventTrigger.java
deleted file mode 100644
index 26c9e5c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/EventTrigger.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import java.util.Map;
-
-interface EventTrigger {
-    void triggerEvent(String type, Map<String, Object> args);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/GapItemDecoration.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/GapItemDecoration.java
deleted file mode 100644
index 96d1770..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/GapItemDecoration.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.view.View;
-
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXViewUtils;
-
-/**
- * Created by furture on 2018/2/12.
- * recyclerview's height is layout width + column gap,
- * so the the offset should include, leftGap and rightGap is via this
- */
-public class GapItemDecoration extends RecyclerView.ItemDecoration {
-
-    private WXListComponent listComponent;
-
-    public GapItemDecoration(WXListComponent listComponent) {
-        this.listComponent = listComponent;
-    }
-
-    @Override
-    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
-        final Float[] spanOffsets = listComponent.getSpanOffsets();
-        if (spanOffsets == null) {
-            return;
-        }
-        int position = parent.getChildAdapterPosition(view);
-        if(position < 0) {
-            return;
-        }
-        if(view.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams){
-            StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
-            if(params.isFullSpan()){
-                return;
-            }
-            WXComponent component = listComponent.getChild(position);
-            if(component instanceof WXCell){
-                WXCell cell = (WXCell) component;
-                if(cell.isFixed() || cell.isSticky()) {
-                    return;
-                }
-
-                if (params.getSpanIndex() >= spanOffsets.length) {
-                    return;
-                }
-
-                int index = listComponent.isLayoutRTL() ? spanOffsets.length - params.getSpanIndex() - 1 : params.getSpanIndex();
-                float spanOffset = listComponent.getSpanOffsets()[index];
-                int   spanOffsetPx =  Math.round(WXViewUtils.getRealPxByWidth(spanOffset, listComponent.getViewPortWidth()));
-                if (listComponent.isLayoutRTL()) {
-                    outRect.left = -spanOffsetPx;
-                    outRect.right = spanOffsetPx;
-                } else {
-                    outRect.left = spanOffsetPx;
-                    outRect.right = -spanOffsetPx;
-                }
-            }
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/HorizontalListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/HorizontalListComponent.java
deleted file mode 100644
index aebde71..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/HorizontalListComponent.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXVContainer;
-
-/**
- * Created by sospartan on 6/2/16.
- */
-@Component(lazyload = false)
-
-public class HorizontalListComponent extends WXListComponent {
-  public HorizontalListComponent(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
-    super(instance, parent, lazy, basicComponentData);
-  }
-
-  @Override
-  public int getOrientation() {
-    return Constants.Orientation.HORIZONTAL;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/ListComponentView.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/ListComponentView.java
deleted file mode 100644
index d29aeec..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/ListComponentView.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-import com.taobao.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
-
-/**
- * Created by sospartan on 13/12/2016.
- */
-
-public interface ListComponentView {
-  WXRecyclerView getInnerView();
-  void setRecyclerViewBaseAdapter(RecyclerViewBaseAdapter adapter);
-  void notifyStickyShow(WXCell component);
-  void notifyStickyRemove(WXCell component);
-  void updateStickyView(int currentStickyPos);
-  RecyclerViewBaseAdapter getRecyclerViewBaseAdapter();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/RecyclerTransform.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/RecyclerTransform.java
deleted file mode 100644
index 15beede..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/RecyclerTransform.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.support.v7.widget.RecyclerView;
-
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.view.listview.adapter.TransformItemDecoration;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * recycler item decoration transform
- * Created by jianbai.gbj on 2017/9/14.
- */
-public class RecyclerTransform {
-
-    public static final String TRANSFORM = Constants.Name.TRANSFORM;
-    private static final Pattern transformPattern = Pattern.compile("([a-z]+)\\(([0-9\\.]+),?([0-9\\.]+)?\\)");
-    private static final String TAG = "RecyclerTransform";
-
-    /**
-     * These transform functions are supported:
-     * - `scale(x,y)`: scale item, x and y should be a positive float number.
-     * - `translate(x,y)`: translate item, `x` and `y` shoule be integer numbers.
-     * - `opacity(n)`: change the transparency of item, `n` must in `[0,1.0]`.
-     * - `rotate(n)`: rotate item, n is integer number.
-     *
-     * @param raw
-     * @return
-     */
-    public static RecyclerView.ItemDecoration parseTransforms(int orientation, String raw) {
-        if (raw == null) {
-            return null;
-        }
-        float scaleX = 0f, scaleY = 0f;
-        int translateX = 0, translateY = 0;
-        float opacity = 0f;
-        int rotate = 0;
-        //public TransformItemDecoration(boolean isVertical,float alpha,int translateX,int translateY,int rotation,float scale)
-        Matcher matcher = transformPattern.matcher(raw);
-        while (matcher.find()) {
-            String match = matcher.group();
-            String name = matcher.group(1);
-            try {
-                switch (name) {
-                    case "scale":
-                        scaleX = Float.parseFloat(matcher.group(2));
-                        scaleY = Float.parseFloat(matcher.group(3));
-                        break;
-                    case "translate":
-                        translateX = Integer.parseInt(matcher.group(2));
-                        translateY = Integer.parseInt(matcher.group(3));
-                        break;
-                    case "opacity":
-                        opacity = Float.parseFloat(matcher.group(2));
-                        break;
-                    case "rotate":
-                        rotate = Integer.parseInt(matcher.group(2));
-                        break;
-                    default:
-                        WXLogUtils.e(TAG, "Invaild transform expression:" + match);
-                        break;
-                }
-            } catch (NumberFormatException e) {
-                WXLogUtils.e("", e);
-                WXLogUtils.e(TAG, "Invaild transform expression:" + match);
-            }
-        }
-        return new TransformItemDecoration(orientation == Constants.Orientation.VERTICAL, opacity, translateX, translateY, rotate, scaleX, scaleY);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/SimpleListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/SimpleListComponent.java
deleted file mode 100644
index 288abe0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/SimpleListComponent.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.content.Context;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-
-/**
- * A simple list component based on regular recyclerview, do not support refreshing and loading.
- * Created by sospartan on 13/12/2016.
- *
- */
-public class SimpleListComponent extends BasicListComponent<SimpleRecyclerView>{
-
-  public SimpleListComponent(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  @Override
-  protected SimpleRecyclerView generateListView(Context context, int orientation) {
-    SimpleRecyclerView view = new SimpleRecyclerView(context);
-    view.initView(context, WXRecyclerView.TYPE_LINEAR_LAYOUT, orientation);
-    return view;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/SimpleRecyclerView.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/SimpleRecyclerView.java
deleted file mode 100644
index 269e804..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/SimpleRecyclerView.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-import com.taobao.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
-
-import java.util.Stack;
-
-/**
- * Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
- * Created by sospartan on 13/12/2016.
- */
-
-class SimpleRecyclerView extends WXRecyclerView implements ListComponentView{
-  private RecyclerViewBaseAdapter mAdapter = null;
-
-  public SimpleRecyclerView(Context context) {
-    super(context);
-  }
-
-  @Override
-  public WXRecyclerView getInnerView() {
-    return this;
-  }
-
-  @Override
-  public void setRecyclerViewBaseAdapter(RecyclerViewBaseAdapter adapter) {
-    setAdapter(adapter);
-    this.mAdapter = adapter;
-  }
-
-  /**
-   * @param component
-   */
-  public void notifyStickyShow(WXCell component) {
-    //Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
-  }
-
-  /**
-   * @param component
-   */
-  public void notifyStickyRemove(WXCell component) {
-    //Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
-  }
-
-  @Override
-  public void updateStickyView(int currentStickyPos) {
-    //Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
-  }
-
-  @Override
-  public RecyclerViewBaseAdapter getRecyclerViewBaseAdapter() {
-    return mAdapter;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/StickyHeaderHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/StickyHeaderHelper.java
deleted file mode 100644
index 5a12e2e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/StickyHeaderHelper.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Created by sospartan on 17/03/2017.
- */
-
-public class StickyHeaderHelper {
-  private final ViewGroup mParent;
-  private Map<String,View> mHeaderViews = new HashMap<>(); // map for <ref,view>
-  private Map<String,WXCell> mHeaderComps = new HashMap<>(); // map for <ref,comp>
-  private String mCurrentStickyRef = null;
-
-  public StickyHeaderHelper(ViewGroup parent){
-    this.mParent = parent;
-  }
-
-  /**
-   * @param component
-   */
-  public void notifyStickyShow(WXCell component) {
-    if (component == null)
-      return;
-    mHeaderComps.put(component.getRef(),component);
-    if(mCurrentStickyRef != null){
-      WXCell cell = mHeaderComps.get(mCurrentStickyRef);
-      if(cell ==null || component.getScrollPositon() > cell.getScrollPositon()){
-        mCurrentStickyRef = component.getRef();
-      }
-    }else{
-      mCurrentStickyRef = component.getRef();
-    }
-
-    {
-      if(mCurrentStickyRef==null){
-        WXLogUtils.e("Current Sticky ref is null.");
-        return;
-      }
-
-      WXCell headComponent = mHeaderComps.get(mCurrentStickyRef);
-      final View headerView = headComponent.getRealView();
-      if (headerView == null) {
-        WXLogUtils.e("Sticky header's real view is null.");
-        return;
-      }
-      View header = mHeaderViews.get(headComponent.getRef());
-      if( header != null){
-        //already there
-        header.bringToFront();
-      }else {
-        mHeaderViews.put(headComponent.getRef(), headerView);
-        //record translation, it should not change after transformation
-        final float translationX = headerView.getTranslationX();
-        final float translationY = headerView.getTranslationY();
-        headComponent.removeSticky();
-
-        ViewGroup existedParent;
-        if ((existedParent = (ViewGroup) headerView.getParent()) != null) {
-          existedParent.removeView(headerView);
-        }
-        headerView.setTag(headComponent.getRef());
-        ViewGroup.MarginLayoutParams mlp =
-                new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
-        mParent.addView(headerView, mlp);
-        headerView.setTag(this);
-        if(headComponent.getStickyOffset() > 0) {
-          ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) headerView.getLayoutParams();
-          if(headComponent.getStickyOffset() != params.topMargin) {
-            params.topMargin = headComponent.getStickyOffset();
-          }
-        }
-        //recover translation, sometimes it will be changed on fling
-        headerView.setTranslationX(translationX);
-        headerView.setTranslationY(translationY);
-      }
-      changeFrontStickyVisible();
-      if (headComponent.getEvents().contains("sticky")) {
-        headComponent.fireEvent("sticky");
-      }
-    }
-  }
-
-
-  public void notifyStickyRemove(WXCell compToRemove) {
-    if (compToRemove == null)
-      return;
-    final WXCell component = mHeaderComps.containsValue(compToRemove) ? mHeaderComps.remove(compToRemove.getRef()) : compToRemove;
-    final View headerView = mHeaderViews.remove(compToRemove.getRef());
-
-    if(component == null || headerView == null){
-      if(WXEnvironment.isApkDebugable()) {
-      }
-      return;
-    }
-    if(mCurrentStickyRef != null && mCurrentStickyRef.equals(compToRemove.getRef())){
-      mCurrentStickyRef = null;
-    }
-    mParent.post(WXThread.secure(new Runnable() {
-      @Override
-      public void run() {
-        mParent.removeView(headerView);
-        if(headerView.getVisibility() != View.VISIBLE){
-          headerView.setVisibility(View.VISIBLE);
-        }
-        component.recoverySticky();
-        changeFrontStickyVisible();
-
-      }
-    }));
-    if (component.getEvents().contains("unsticky")) {
-      component.fireEvent("unsticky");
-    }
-  }
-
-
-  public void updateStickyView(int currentStickyPos) {
-    Iterator<Map.Entry<String, WXCell>> iterator = mHeaderComps.entrySet().iterator();
-    List<WXCell> toRemove = new ArrayList<>();
-    while(iterator.hasNext()){
-      Map.Entry<String, WXCell> next = iterator.next();
-      WXCell cell = next.getValue();
-      int pos = cell.getScrollPositon();
-      if(pos > currentStickyPos){
-        toRemove.add(cell);
-      }else if(pos == currentStickyPos){
-        mCurrentStickyRef = cell.getRef();
-        View view = mHeaderViews.get(cell.getRef());
-        if(view != null){
-          view.bringToFront();
-          changeFrontStickyVisible();
-        }
-      }
-    }
-    for(WXCell cell:toRemove){
-      notifyStickyRemove(cell);
-    }
-  }
-
-  public void  clearStickyHeaders(){
-    if(mHeaderViews.size() <= 0){
-      return;
-    }
-    Iterator<Map.Entry<String, WXCell>> iterator = mHeaderComps.entrySet().iterator();
-
-    while (iterator.hasNext()) {
-      Map.Entry<String, WXCell> next = iterator.next();
-      WXCell value = next.getValue();
-      iterator.remove();
-      notifyStickyRemove(value);
-    }
-  }
-
-
-  private void changeFrontStickyVisible(){
-    if(mHeaderViews.size() <= 0){
-      return;
-    }
-    boolean  fontVisible = false;
-    for(int i=mParent.getChildCount()-1; i>=0; i--){
-      View view = mParent.getChildAt(i);
-      if(fontVisible && view.getTag() instanceof  StickyHeaderHelper){
-        if(view.getVisibility() != View.GONE){
-          view.setVisibility(View.GONE);
-        }
-      }else{
-        if(view.getTag() instanceof  StickyHeaderHelper){
-          fontVisible = true;
-          if(view != null && view.getVisibility() != View.VISIBLE){
-            view.setVisibility(View.VISIBLE);
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java
deleted file mode 100644
index 1687545..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.content.Context;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXHeader;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.flat.WidgetContainer;
-import com.taobao.weex.ui.view.WXFrameLayout;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import org.w3c.dom.Text;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.LinkedList;
-
-import static com.taobao.weex.common.Constants.Name.STICKY_OFFSET;
-
-/**
- * Root component for components in {@link WXListComponent}
- */
-@Component(lazyload = false)
-
-public class WXCell extends WidgetContainer<WXFrameLayout> {
-
-    private int mLastLocationY = 0;
-    private ViewGroup mRealView;
-    private View mTempStickyView;
-    private View mHeadView;
-
-    /** used in list sticky detect **/
-    private int mScrollPosition = -1;
-    private boolean mFlatUIEnabled = false;
-
-
-    private Object  renderData;
-
-    private boolean isSourceUsed = false;
-
-    private boolean isAppendTreeDone;
-
-    private CellAppendTreeListener cellAppendTreeListener;
-
-    public static class Creator implements ComponentCreator {
-        public WXComponent createInstance(WXSDKInstance instance,
-                                          WXVContainer parent,
-                                          BasicComponentData basicComponentData)
-                throws IllegalAccessException, InvocationTargetException, InstantiationException {
-            return new WXCell(instance, parent, true, basicComponentData);
-        }
-    }
-
-    @Deprecated
-    public WXCell(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-        super(instance, parent, basicComponentData);
-    }
-
-    public WXCell(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
-        super(instance, parent, basicComponentData);
-        lazy(true);
-        if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP) {
-            try {
-                //TODO a WTF is necessary if anyone try to change the flat flag during update attrs.
-                WXAttr attr = getAttrs();
-                if (attr.containsKey(Constants.Name.FLAT)) {
-                    mFlatUIEnabled = WXUtils.getBoolean(attr.get(Constants.Name.FLAT), false);
-                }
-            } catch (NullPointerException e) {
-                WXLogUtils.e("Cell", WXLogUtils.getStackTrace(e));
-            }
-        }
-        if (!canRecycled()){
-            instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM,1);
-        }
-        if (TextUtils.isEmpty(getAttrs().getScope())){
-            instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_UN_RE_USE_NUM,1);
-        }
-    }
-
-    @Override
-    public boolean isLazy() {
-        return super.isLazy() && !isFixed();
-    }
-
-    @Override
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public boolean isFlatUIEnabled() {
-        return mFlatUIEnabled;
-    }
-
-    /**
-     * If Cell is Sticky, need wraped FrameLayout
-     */
-    @Override
-    protected WXFrameLayout initComponentHostView(@NonNull Context context) {
-        if (isSticky() || this instanceof WXHeader) {
-            WXFrameLayout view = new WXFrameLayout(context);
-            mRealView = new WXFrameLayout(context);
-            view.addView(mRealView);
-            //TODO Maybe there is a better solution for hardware-acceleration view's display list.
-            if (isFlatUIEnabled()) {
-                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            }
-            return view;
-        } else {
-            WXFrameLayout view = new WXFrameLayout(context);
-            mRealView = view;
-            if (isFlatUIEnabled()) {
-                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            }
-            return view;
-        }
-    }
-
-    public int getLocationFromStart(){
-        return mLastLocationY;
-    }
-
-    public void setLocationFromStart(int l){
-        mLastLocationY = l;
-    }
-
-    void setScrollPositon(int pos){
-        mScrollPosition = pos;
-    }
-
-    public int getScrollPositon() {
-        return mScrollPosition;
-    }
-
-    @Override
-    public ViewGroup getRealView() {
-        return mRealView;
-    }
-
-    public void removeSticky() {
-        if(getHostView().getChildCount() > 0) {
-            mHeadView = getHostView().getChildAt(0);
-            int[] location = new int[2];
-            int[] parentLocation = new int[2];
-            getHostView().getLocationOnScreen(location);
-            getParentScroller().getView().getLocationOnScreen(parentLocation);
-            int headerViewOffsetX = location[0] - parentLocation[0];
-            int headerViewOffsetY = getParent().getHostView().getTop();
-            getHostView().removeView(mHeadView);
-            mRealView = (ViewGroup) mHeadView;
-            mTempStickyView = new FrameLayout(getContext());
-            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) getLayoutWidth(),
-                    (int) getLayoutHeight());
-            getHostView().addView(mTempStickyView, lp);
-            mHeadView.setTranslationX(headerViewOffsetX);
-            mHeadView.setTranslationY(headerViewOffsetY);
-        }
-    }
-
-    public void recoverySticky() {
-        if(mHeadView != null){
-            if(mHeadView.getLayoutParams() != null){
-                ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mHeadView.getLayoutParams();
-                if(params.topMargin > 0){
-                    params.topMargin = 0;
-                }
-            }
-            if(mHeadView.getVisibility() != View.VISIBLE){
-                mHeadView.setVisibility(View.VISIBLE);
-            }
-            if(mHeadView.getParent() != null){
-                ((ViewGroup)mHeadView.getParent()).removeView(mHeadView);
-            }
-            getHostView().removeView(mTempStickyView);
-            getHostView().addView(mHeadView);
-            mHeadView.setTranslationX(0);
-            mHeadView.setTranslationY(0);
-        }
-    }
-
-    @Override
-    protected void mountFlatGUI() {
-        if(getHostView()!=null) {
-            if(widgets == null){
-                widgets = new LinkedList<>();
-            }
-            getHostView().mountFlatGUI(widgets);
-        }
-    }
-
-    @Override
-    public void unmountFlatGUI() {
-        if (getHostView() != null) {
-            getHostView().unmountFlatGUI();
-        }
-    }
-
-    @Override
-    public boolean intendToBeFlatContainer() {
-        return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXCell.class.equals(getClass()) && !isSticky();
-    }
-
-    public int getStickyOffset(){
-        if(getAttrs().get(STICKY_OFFSET) == null){
-            return 0;
-        }
-        float  offset = WXUtils.getFloat(getAttrs().get(STICKY_OFFSET));
-        return (int)(WXViewUtils.getRealPxByWidth(offset, getViewPortWidth()));
-    }
-
-    public Object getRenderData() {
-        return renderData;
-    }
-
-    public void setRenderData(Object renderData) {
-        this.renderData = renderData;
-    }
-
-    public boolean isSourceUsed() {
-        return isSourceUsed;
-    }
-
-    public void setSourceUsed(boolean sourceUsed) {
-        isSourceUsed = sourceUsed;
-    }
-
-
-    public boolean isAppendTreeDone(){
-        return isAppendTreeDone;
-    }
-
-    @Override
-    public void appendTreeCreateFinish() {
-        super.appendTreeCreateFinish();
-        isAppendTreeDone = true;
-        if(cellAppendTreeListener != null){
-            cellAppendTreeListener.onAppendTreeDone();
-        }
-    }
-
-    public void setCellAppendTreeListener(CellAppendTreeListener cellAppendTreeListener) {
-        this.cellAppendTreeListener = cellAppendTreeListener;
-        if(isAppendTreeDone){
-            cellAppendTreeListener.onAppendTreeDone();
-        }
-    }
-
-    public interface CellAppendTreeListener{
-        public void onAppendTreeDone();
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java
deleted file mode 100644
index 95364e1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import static com.taobao.weex.ui.view.listview.WXRecyclerView.TYPE_LINEAR_LAYOUT;
-
-import android.content.Context;
-import android.support.v4.util.ArrayMap;
-import android.support.v7.widget.PagerSnapHelper;
-import android.text.TextUtils;
-import com.alibaba.fastjson.JSON;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXBaseRefresh;
-import com.taobao.weex.ui.component.WXBasicComponentType;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXComponentProp;
-import com.taobao.weex.ui.component.WXLoading;
-import com.taobao.weex.ui.component.WXRefresh;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-import com.taobao.weex.ui.view.listview.adapter.ListBaseViewHolder;
-import com.taobao.weex.ui.view.refresh.wrapper.BounceRecyclerView;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Unlike other components, there is immutable bi-directional association between View and
- * ViewHolder, while only mutable and temporal uni-directional association between view and
- * components. The association only exist from {@link #onBindViewHolder(ListBaseViewHolder, int)} to
- * {@link #onViewRecycled(ListBaseViewHolder)}. In other situations, the association may not valid
- * or not even exist.
- */
-@Component(lazyload = false)
-
-public class WXListComponent extends BasicListComponent<BounceRecyclerView> {
-  private String TAG = "WXListComponent";
-  //  private WXRecyclerDomObject mDomObject;
-  private float mPaddingLeft;
-  private float mPaddingRight;
-  private String mSpanOffsetsStr;
-  private Float[] mSpanOffsets;
-  private boolean hasSetGapItemDecoration = false;
-
-  public static class Creator implements ComponentCreator {
-    public WXComponent createInstance(WXSDKInstance instance,
-                                      WXVContainer parent,
-                                      BasicComponentData basicComponentData)
-            throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      return new WXListComponent(instance, parent, true, basicComponentData);
-    }
-  }
-
-  @Deprecated
-  public WXListComponent(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
-    this(instance, parent, isLazy, basicComponentData);
-  }
-
-
-  public WXListComponent(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  @Override
-  protected BounceRecyclerView generateListView(Context context, int orientation) {
-    BounceRecyclerView bounceRecyclerView = new BounceRecyclerView(context, mLayoutType, mColumnCount, mColumnGap, orientation);
-    if (bounceRecyclerView.getSwipeLayout() != null) {
-      if (WXUtils.getBoolean(getAttrs().get(Constants.Name.NEST_SCROLLING_ENABLED), false)) {
-        bounceRecyclerView.getSwipeLayout().setNestedScrollingEnabled(true);
-      }
-    }
-
-    /**
-     *  enable pagingEnabled attr
-     */
-    if(WXUtils.getBoolean(getAttrs().get(Constants.Name.PAGE_ENABLED),false)){
-      PagerSnapHelper snapHelper = null;
-      String pageSize = WXUtils.getString(getAttrs().get(Constants.Name.PAGE_SIZE), null);
-      if(TextUtils.isEmpty(pageSize)) {
-        snapHelper = new PagerSnapHelper();
-      } else  {
-        snapHelper = new WXPagerSnapHelper();
-      }
-
-      snapHelper.attachToRecyclerView(bounceRecyclerView.getInnerView());
-    }
-
-    return bounceRecyclerView;
-  }
-
-  @Override
-  public void addChild(WXComponent child, int index) {
-    super.addChild(child, index);
-    if (child == null || index < -1) {
-      return;
-    }
-    setRefreshOrLoading(child);
-    // Synchronize DomObject's attr to Component and Native View
-    if(getHostView() != null && hasColumnPros()) {
-      updateRecyclerAttr();
-      getHostView().getInnerView().initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
-    }
-  }
-
-  private boolean hasColumnPros() {
-    return (getAttrs().containsKey(Constants.Name.COLUMN_WIDTH) && mColumnWidth != WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_WIDTH))) ||
-            (getAttrs().containsKey(Constants.Name.COLUMN_COUNT) &&  mColumnCount != WXUtils.parseInt(getAttrs().get(Constants.Name.COLUMN_COUNT))) ||
-            (getAttrs().containsKey(Constants.Name.COLUMN_GAP) && mColumnGap != WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_GAP)));
-  }
-
-  /**
-   * Setting refresh view and loading view
-   *
-   * @param child the refresh_view or loading_view
-   */
-  private boolean setRefreshOrLoading(final WXComponent child) {
-
-    if (getHostView() == null) {
-      WXLogUtils.e(TAG, "setRefreshOrLoading: HostView == null !!!!!! check list attr has append =tree");
-      return true;
-    }
-    if (child instanceof WXRefresh) {
-      getHostView().setOnRefreshListener((WXRefresh) child);
-      getHostView().postDelayed(WXThread.secure(new Runnable() {
-        @Override
-        public void run() {
-          getHostView().setHeaderView(child);
-        }
-      }), 100);
-      return true;
-    }
-
-    if (child instanceof WXLoading) {
-      getHostView().setOnLoadingListener((WXLoading) child);
-      getHostView().postDelayed(WXThread.secure(new Runnable() {
-        @Override
-        public void run() {
-          getHostView().setFooterView(child);
-        }
-      }), 100);
-      return true;
-    }
-    return false;
-  }
-
-  private void updateRecyclerAttr() {
-    mColumnCount = WXUtils.parseInt(getAttrs().get(Constants.Name.COLUMN_COUNT));
-    if (mColumnCount <= 0 && mLayoutType != TYPE_LINEAR_LAYOUT) {
-      Map<String, String> ext = new ArrayMap<>();
-      ext.put("componentType", getComponentType());
-      ext.put("attribute", getAttrs().toString());
-      ext.put("stackTrace", Arrays.toString(Thread.currentThread().getStackTrace()));
-      WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
-          WXErrorCode.WX_RENDER_ERR_LIST_INVALID_COLUMN_COUNT, "columnCount",
-          String.format(Locale.ENGLISH,
-              "You are trying to set the list/recycler/vlist/waterfall's column to %d, which is illegal. The column count should be a positive integer",
-              mColumnCount),
-          ext);
-      mColumnCount = Constants.Value.COLUMN_COUNT_NORMAL;
-    }
-    mColumnGap = WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_GAP));
-    mColumnWidth = WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_WIDTH));
-    mPaddingLeft = WXUtils.parseFloat(getAttrs().get(Constants.Name.PADDING_LEFT));
-    mPaddingRight = WXUtils.parseFloat(getAttrs().get(Constants.Name.PADDING_RIGHT));
-    mSpanOffsetsStr = (String)getAttrs().get(Constants.Name.SPAN_OFFSETS);
-
-    try {
-      if (!TextUtils.isEmpty(mSpanOffsetsStr)) {
-        List<Float> list = JSON.parseArray(mSpanOffsetsStr, Float.class);
-        final int size = list.size();
-        if (null == mSpanOffsets || mSpanOffsets.length != size) {
-          mSpanOffsets = new Float[size];
-        }
-        list.toArray(mSpanOffsets);
-      } else {
-        mSpanOffsets = null;
-      }
-    } catch (Throwable e) {
-      WXLogUtils.w("Parser SpanOffsets error ", e);
-    }
-
-    if (!hasSetGapItemDecoration && null != getSpanOffsets() && null != getHostView()
-        && null != getHostView().getInnerView()) {
-      hasSetGapItemDecoration = true;
-      getHostView().getInnerView().addItemDecoration(new GapItemDecoration(this));
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SPAN_OFFSETS)
-  public void setSpanOffsets(String spanOffsets)  {
-    if (!TextUtils.equals(spanOffsets, mSpanOffsetsStr)) {
-      markComponentUsable();
-      updateRecyclerAttr();
-      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-      wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.COLUMN_WIDTH)
-  public void setColumnWidth(float columnWidth)  {
-    if(columnWidth != mColumnWidth){
-      markComponentUsable();
-      updateRecyclerAttr();
-      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-      wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.COLUMN_COUNT)
-  public void setColumnCount(int columnCount){
-    if(columnCount != mColumnCount) {
-      markComponentUsable();
-      updateRecyclerAttr();
-      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-      wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.COLUMN_GAP)
-  public void setColumnGap(float columnGap) throws InterruptedException {
-    if(columnGap != mColumnGap) {
-      markComponentUsable();
-      updateRecyclerAttr();
-      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-      wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
-    }
-  }
-
-  @WXComponentProp(name = Constants.Name.SCROLLABLE)
-  public void setScrollable(boolean scrollable) {
-    WXRecyclerView inner = getHostView().getInnerView();
-    inner.setScrollable(scrollable);
-  }
-
-  @Override
-  public void updateProperties(Map<String, Object> props) {
-    super.updateProperties(props);
-    if (isRecycler(this)) {
-      if(WXBasicComponentType.WATERFALL.equals(getComponentType())){
-        mLayoutType = WXRecyclerView.TYPE_STAGGERED_GRID_LAYOUT;
-      }else{
-        mLayoutType = getAttrs().getLayoutType();
-      }
-    }
-
-    if(props.containsKey(Constants.Name.PADDING)
-            ||props.containsKey(Constants.Name.PADDING_LEFT)
-            || props.containsKey(Constants.Name.PADDING_RIGHT)){
-      if(mPaddingLeft != WXUtils.parseFloat(props.get(Constants.Name.PADDING_LEFT)) || mPaddingRight != WXUtils.parseFloat(props.get(Constants.Name.PADDING_RIGHT))) {
-        markComponentUsable();
-        updateRecyclerAttr();
-        WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-        wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
-      }
-    }
-  }
-
-  @Override
-  public void createChildViewAt(int index) {
-    int indexToCreate = index;
-    if (indexToCreate < 0) {
-      indexToCreate = childCount() - 1;
-      if (indexToCreate < 0) {
-        return;
-      }
-    }
-    final WXComponent child = getChild(indexToCreate);
-    if (child instanceof WXBaseRefresh) {
-      child.createView();
-      if (child instanceof WXRefresh) {
-        getHostView().setOnRefreshListener((WXRefresh) child);
-        getHostView().postDelayed(new Runnable() {
-          @Override
-          public void run() {
-            getHostView().setHeaderView(child);
-          }
-        }, 100);
-      } else if (child instanceof WXLoading) {
-        getHostView().setOnLoadingListener((WXLoading) child);
-        getHostView().postDelayed(new Runnable() {
-          @Override
-          public void run() {
-            getHostView().setFooterView(child);
-          }
-        }, 100);
-      }
-    } else {
-      super.createChildViewAt(indexToCreate);
-    }
-  }
-
-  public void remove(WXComponent child, boolean destroy) {
-    super.remove(child, destroy);
-    removeFooterOrHeader(child);
-  }
-
-  private void removeFooterOrHeader(WXComponent child) {
-    if (child instanceof WXLoading) {
-      getHostView().removeFooterView(child);
-    } else if (child instanceof WXRefresh) {
-      getHostView().removeHeaderView(child);
-    }
-  }
-
-  private boolean isRecycler(WXComponent component) {
-    return WXBasicComponentType.WATERFALL.equals(component.getComponentType())
-            || WXBasicComponentType.RECYCLE_LIST.equals(component.getComponentType())
-            || WXBasicComponentType.RECYCLER.equals(component.getComponentType());
-  }
-
-  public Float[] getSpanOffsets() {
-    return mSpanOffsets;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXPagerSnapHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXPagerSnapHelper.java
deleted file mode 100644
index 633ac0c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXPagerSnapHelper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.OrientationHelper;
-import android.support.v7.widget.PagerSnapHelper;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-public class WXPagerSnapHelper extends PagerSnapHelper {
-    @Nullable
-    private OrientationHelper mVerticalHelper;
-    @Nullable
-    private OrientationHelper mHorizontalHelper;
-
-    @Nullable
-    @Override
-    public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
-
-        int[] out = new int[2];
-        if (layoutManager.canScrollHorizontally()) {
-            out[0] = this.distanceToStart(layoutManager, targetView, this.getHorizontalHelper(layoutManager));
-        } else {
-            out[0] = 0;
-        }
-
-        if (layoutManager.canScrollVertically()) {
-            out[1] = this.distanceToStart(layoutManager, targetView, this.getVerticalHelper(layoutManager));
-        } else {
-            out[1] = 0;
-        }
-
-        return out;
-    }
-
-    @NonNull
-    private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
-        if (this.mVerticalHelper == null) {
-            this.mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
-        }
-
-        return this.mVerticalHelper;
-    }
-
-    @NonNull
-    private OrientationHelper getHorizontalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
-        if (this.mHorizontalHelper == null) {
-            this.mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
-        }
-
-        return this.mHorizontalHelper;
-    }
-
-    private int distanceToStart(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
-        return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/AsyncCellLoadTask.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/AsyncCellLoadTask.java
deleted file mode 100644
index d186c81..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/AsyncCellLoadTask.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import android.os.AsyncTask;
-import android.os.Looper;
-import android.os.MessageQueue;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * Created by furture on 2018/1/25.
- * async template cell component copy in background and init component when idle
- */
-class AsyncCellLoadTask extends AsyncTask<Void,Void, Void> {
-
-    private String template;
-    private WXCell source;
-    private WXRecyclerTemplateList templateList;
-
-    public AsyncCellLoadTask(String template, WXCell source, WXRecyclerTemplateList templateList) {
-        this.template = template;
-        this.source = source;
-        this.templateList = templateList;
-    }
-
-    /**
-     * async template cell component copy in background
-     * */
-    @Override
-    protected Void doInBackground(Void... params) {
-        TemplateCache cellCache = templateList.getTemplatesCache().get(template);
-        if(cellCache == null || cellCache.cells == null){
-            return null;
-        }
-        while (cellCache.cells.size() < templateList.getTemplateCacheSize()){
-            long start = System.currentTimeMillis();
-            WXCell component = (WXCell) templateList.copyComponentFromSourceCell(source);
-            if(WXEnvironment.isOpenDebugLog() && WXRecyclerTemplateList.ENABLE_TRACE_LOG){
-                WXLogUtils.d(WXRecyclerTemplateList.TAG, " AsyncCellLoadTask load " + template
-                        + "  " +  component.hashCode()
-                + " used " + (System.currentTimeMillis() - start));
-            }
-            if(component == null){
-                return null;
-            }
-            if(isDestory()){
-                return null;
-            }
-            cellCache.cells.add(component);
-        }
-        return null;
-    }
-
-    /**
-     * init component view when main thread idle
-     * */
-    @Override
-    protected void onPostExecute(Void aVoid) {
-        if(isDestory()){
-            return;
-        }
-        final TemplateCache cellCache = templateList.getTemplatesCache().get(template);
-        if(cellCache == null){
-            return;
-        }
-        if(cellCache.cells == null
-                || cellCache.cells.size() == 0){
-            cellCache.isLoadIng = false;
-            return;
-        }
-        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
-            @Override
-            public boolean queueIdle() {
-                if(isDestory()){
-                    return false;
-                }
-                ConcurrentLinkedQueue<WXCell> queue =  cellCache.cells;
-                Iterator<WXCell> iterator =  queue.iterator();
-                while (iterator.hasNext()){
-                    WXCell component =  iterator.next();
-                    if(component.isLazy()){
-                        templateList.doCreateCellViewBindData(component, template, true);
-                        return iterator.hasNext();
-                    }
-                }
-                return false;
-            }
-        });
-        cellCache.isLoadIng = false;
-    }
-
-    private boolean isDestory(){
-        if(source.getInstance() == null
-                || source.getInstance().isDestroy()){
-            return true;
-        }
-        return templateList.isDestoryed();
-    }
-
-    /**
-     * start cell load task on THREAD_POOL_EXECUTOR
-     * */
-    public void startTask(){
-        executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellDataManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellDataManager.java
deleted file mode 100644
index 5b75346..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellDataManager.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSONArray;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by furture on 2018/1/23.
- * template data manager, manage data and render state
- */
-public class CellDataManager {
-
-    private static final String VIRTUAL_COMPONENT_SEPRATOR = "@";
-
-    public static final String SUB_COMPONENT_TEMPLATE_ID = "@templateId";
-
-    public static final String VIRTUAL_COMPONENT_ID = "@virtualComponentId";
-
-    /**
-     * template list data, update should vis data manager interface, this field is read only
-     * */
-    JSONArray listData;
-
-    /**
-     * current template list
-     * */
-    public final WXRecyclerTemplateList templateList;
-
-    /**
-     * data render state for position, itemId、dirty、and other info
-     * */
-    private Map<Integer, CellRenderState> renderStates = new ArrayMap<>();
-
-
-    /**
-     * list virtual component data, rendet state
-     * key virtual component id, value is cell render state.
-     * */
-    private Map<String, CellRenderState> virtualComponentRenderStates;
-
-
-
-    /**
-     * template list data manager
-     * */
-    public CellDataManager(WXRecyclerTemplateList templateList) {
-        this.templateList = templateList;
-    }
-
-    /**
-     * get current render state for current position, never return null.
-     * */
-    public CellRenderState getRenderState(int position){
-        CellRenderState renderState = renderStates.get(position);
-        if(renderState == null){
-            renderState = new CellRenderState();
-            renderState.position = position;
-            renderStates.put(position, renderState);
-        }
-        if(position != renderState.position) {
-            renderState.position = position;
-            renderState.hasPositionChange = true;
-        }
-        return renderState;
-    }
-
-    /**
-     * @param  virutalComponentId virutalComponentId
-     * @param  data   update    virutalComponent's data
-     * update virtual component data
-     * */
-    public void updateVirtualComponentData(String virutalComponentId, Object data){
-        if(virtualComponentRenderStates != null){
-            CellRenderState cellRenderState = virtualComponentRenderStates.get(virutalComponentId);
-            if(cellRenderState != null){
-                cellRenderState.getVirtualComponentDatas().put(virutalComponentId, data);
-                cellRenderState.hasVirtualCompoentUpdate = true;
-            }else{
-                if(WXEnvironment.isApkDebugable()) {
-                    throw new IllegalArgumentException("virtualComponentDatas illegal state empty render state" + virutalComponentId);
-                }
-            }
-        }else{
-            if(WXEnvironment.isApkDebugable()){
-                throw  new IllegalArgumentException("virtualComponentDatas illegal state " + virutalComponentId);
-            }
-        }
-    }
-
-    /**
-     * @param  position  current position virtual component
-     * @param  virutalComponentId virutalComponentId
-     * @param  data   update    virutalComponent's data
-     * create virtual component data
-     * */
-    public void createVirtualComponentData(int position, String virutalComponentId, Object data){
-        if(virtualComponentRenderStates == null){
-            virtualComponentRenderStates = new HashMap<>(8);
-        }
-        CellRenderState renderState = renderStates.get(position);
-        renderState.getVirtualComponentDatas().put(virutalComponentId, data);
-        virtualComponentRenderStates.put(virutalComponentId, renderState);
-
-    }
-
-
-
-
-    /**
-     * @param  listData setList data
-     * clear render state for current cell, and virtual component data
-     * */
-    public void setListData(JSONArray listData) {
-        if(this.listData != listData) {
-            if(this.listData != null){
-                if(WXUtils.getBoolean(templateList.getAttrs().get("exitDetach"), true)){
-                    for(int i=0; i<this.listData.size(); i++){
-                        cleanRenderState(renderStates.remove(i));
-                    }
-                }
-            }
-            this.listData = listData;
-            renderStates.clear();
-            if (virtualComponentRenderStates != null) {
-                virtualComponentRenderStates.clear();
-            }
-        }
-    }
-
-    /**
-     * @param index insert index
-     * @param  data  data object
-     * insert data at current index
-     * */
-    public boolean insertData(int index, Object data){
-        listData.add(index, data);
-        boolean renderStateChange = false;
-        for(int i=listData.size(); i>= index; i--){
-            CellRenderState state = renderStates.remove(i);
-            if(state != null){
-                renderStates.put(i + 1, state);
-                renderStateChange = true;
-            }
-        }
-        return renderStateChange;
-    }
-
-    /**
-     *
-     * @param index insert index
-     * @param  data  data object
-     * insert data at current index
-     * */
-    public boolean insertRange(int index, JSONArray data){
-        listData.addAll(index, data);
-        boolean renderStateChange = false;
-        for(int i = listData.size()-1; i >= index; i--){
-            CellRenderState state = renderStates.remove(i);
-            if(state != null){
-                renderStates.put(i + 1, state);
-                renderStateChange = true;
-            }
-        }
-        return renderStateChange;
-    }
-
-    /**
-     * @param  data  data object
-     * @param index insert index
-     * update data, reset new render state,
-     * return true if only data changed, false if viewType changed
-     * */
-    public boolean  updateData(Object data, int index){
-        boolean onlyDataChange = TextUtils.equals(templateList.getTemplateKey(index), templateList.getTemplateKey(data));
-        listData.set(index, data);
-        if(!onlyDataChange){
-            //structure changed, reset render state
-            cleanRenderState(renderStates.remove(index));
-        }else{
-            CellRenderState renderState = renderStates.get(index);
-            if(renderState != null){
-                renderState.hasDataUpdate = true;
-            }
-        }
-        return onlyDataChange;
-    }
-
-    /**
-     * @param index
-     * remove data, and its render state  and  virtual's data
-     * */
-    public void  removeData(Integer index){
-        listData.remove((int)index); //remove by index
-        cleanRenderState(renderStates.remove(index));
-        int count = listData.size() + 1;
-        for(int i=index + 1; i < count; i++){
-            CellRenderState state = renderStates.remove(i);
-            if(state != null){
-                renderStates.put(i-1, state);
-            }
-        }
-    }
-
-    /**
-     *  clean render state, if has virtual component, call virtual component detach lifecycle
-     * */
-    private void  cleanRenderState(CellRenderState renderState){
-        if(renderState == null){
-            return;
-        }
-        if(renderState.hasVirtualComponents()){
-            Collection<String> virtualComponentIds =  renderState.getVirtualComponentIds().values();
-            for(String virtualComponentId : virtualComponentIds){
-                if(virtualComponentRenderStates != null){
-                    virtualComponentRenderStates.remove(virtualComponentId);
-                }
-                WXBridgeManager.getInstance().asyncCallJSEventVoidResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC,
-                        templateList.getInstanceId(),
-                        null,
-                        virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.DETACH, null);
-
-            }
-        }
-    }
-
-
-    /**
-     * create virtualComponentId
-     * */
-    public static String createVirtualComponentId(String listRef, String viewTreeKey, long itemId){
-        return  listRef + VIRTUAL_COMPONENT_SEPRATOR  + viewTreeKey + VIRTUAL_COMPONENT_SEPRATOR + itemId;
-    }
-
-    /**
-     * get list ref from virtualComponentId
-     * */
-    public static String getListRef(String virtualComponentId){
-        if(virtualComponentId == null){
-            return null;
-        }
-        return virtualComponentId.split(VIRTUAL_COMPONENT_SEPRATOR)[0];
-    }
-    
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellRenderContext.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellRenderContext.java
deleted file mode 100644
index 36fea10..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellRenderContext.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import com.taobao.weex.el.parse.ArrayStack;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by furture on 2018/1/23.
- * render context for cell template
- */
-public class CellRenderContext {
-    /**
-     * code execute stack
-     * */
-    public ArrayStack stack = new ArrayStack();
-    /**
-     * init context data
-     * */
-    public Map map = new HashMap(8);
-
-
-    /**
-     * component data context
-     * */
-    public CellRenderState renderState;
-
-    /**
-     * current position
-     * */
-    public int position;
-
-    /**
-     * current list component
-     * */
-    public WXRecyclerTemplateList templateList;
-
-
-    /**
-     * get current render state
-     * */
-    public CellRenderState getRenderState() {
-        if(renderState != null) {
-            renderState =  templateList.getCellDataManager().getRenderState(position);
-        }
-        return renderState;
-    }
-
-
-    public void clear(){
-        if(stack.getList().size() > 0) {
-            stack.getList().clear();
-        }
-        if(map.size() > 0) {
-            map.clear();
-        }
-        renderState  = null;
-        position = 0;
-        templateList = null;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellRenderState.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellRenderState.java
deleted file mode 100644
index 2f71a81..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellRenderState.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import android.support.v7.widget.RecyclerView;
-
-import com.taobao.weex.el.parse.ArrayStack;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by furture on 2018/1/24.
- * render state for one cell, manage it's render state
- */
-public class CellRenderState {
-
-    /**
-     * dirty for current position, for example virtual component has update
-     * */
-    boolean hasVirtualCompoentUpdate = false;
-
-    /**
-     * has date update
-     * */
-    boolean hasDataUpdate = false;
-
-    /**
-     * position changed
-     * */
-    boolean hasPositionChange = false;
-
-    /**
-     *  may use position, when position changed should be rendered
-     * */
-    int  position;
-
-    /**
-     * unique itemId for current position, generate via key core
-     * */
-    long itemId = RecyclerView.NO_ID;
-
-
-
-    /**
-     * virtualCompoentId for cell, key is viewTreeKey, value is virutalComponentId.
-     * lazy init,
-     * */
-    private Map<String, String> virtualComponentIds;
-    private Map<String, Object> virtualComponentDatas;
-
-
-    /**
-     * mark once statements has rendered
-     * */
-    private Map<String,ArrayStack> onceComponentStates;
-
-
-    public Map<String, String> getVirtualComponentIds() {
-        if(virtualComponentIds == null){
-            virtualComponentIds = new HashMap<>(8);
-        }
-        return virtualComponentIds;
-    }
-
-    /**
-     * return current cell has virtual component
-     * */
-    public boolean hasVirtualComponents(){
-        return virtualComponentIds != null && virtualComponentIds.size() > 0;
-    }
-
-    public Map<String, Object> getVirtualComponentDatas() {
-        if(virtualComponentDatas == null){
-            virtualComponentDatas = new HashMap<>(4);
-        }
-        return virtualComponentDatas;
-    }
-
-    public Map<String, ArrayStack> getOnceComponentStates() {
-        if(onceComponentStates == null){
-            onceComponentStates = new HashMap<>();
-        }
-        return onceComponentStates;
-    }
-
-    public boolean isDirty() {
-        return hasDataUpdate
-                || hasVirtualCompoentUpdate
-                || hasPositionChange;
-    }
-
-    public boolean isHasDataUpdate() {
-        return hasDataUpdate;
-    }
-
-
-
-    public void  resetDirty(){
-        hasDataUpdate = false;
-        hasVirtualCompoentUpdate = false;
-        hasPositionChange = false;
-    }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/PositionRef.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/PositionRef.java
deleted file mode 100644
index d176302..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/PositionRef.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import com.alibaba.fastjson.JSONAware;
-import com.alibaba.fastjson.annotation.JSONType;
-
-/**
- * position render state, when render state change, position changed
- * Created by furture on 2018/2/2.
- */
-public class PositionRef extends  Number implements JSONAware {
-
-    private CellRenderState renderState;
-
-    public PositionRef(CellRenderState renderState) {
-        this.renderState = renderState;
-    }
-
-    @Override
-    public int intValue() {
-        return getPosition();
-    }
-
-    @Override
-    public long longValue() {
-        return getPosition();
-    }
-
-    @Override
-    public float floatValue() {
-        return getPosition();
-    }
-
-    @Override
-    public double doubleValue() {
-        return getPosition();
-    }
-
-    private int getPosition(){
-        if(renderState == null){
-            return  -1;
-        }
-        return renderState.position;
-    }
-
-    @Override
-    public String toString() {
-        return String.valueOf(getPosition());
-    }
-
-    @Override
-    public String toJSONString() {
-        return String.valueOf(getPosition());
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/Selector.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/Selector.java
deleted file mode 100644
index 3765c81..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/Selector.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import android.text.TextUtils;
-
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.component.list.WXCell;
-
-import java.util.List;
-
-/**
- * Created by furture on 2018/7/24.
- */
-
-public class Selector {
-
-    /**
-     * @param  selector  [att=xx]
-     * query elements match selector, current only support attr selector
-     * */
-    public static void queryElementAll(WXComponent component, String selector, List<WXComponent> componentList){
-        if(TextUtils.isEmpty(selector)){
-            return;
-        }
-        selector = selector.replaceAll("\\[|]", "");
-        String[] args = selector.split("=");
-        if(args.length <= 0){
-            return;
-        }
-        String key = args[0];
-        String value = null;
-        if(args.length > 1){
-            value = args[1].trim();
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            for(int i=0; i<container.getChildCount(); i++){
-                queryElementAllByAttrs(container.getChild(i), key, value, componentList);
-            }
-        }
-    }
-
-
-    public static void closest(WXComponent component, String selector,List<WXComponent> componentList){
-        if(TextUtils.isEmpty(selector)){
-            return;
-        }
-        selector = selector.replaceAll("\\[|]", "");
-        String[] args = selector.split("=");
-        if(args.length <= 0){
-            return;
-        }
-        String key = args[0];
-        String value = null;
-        if(args.length > 1){
-            value = args[1].trim();
-        }
-        closestByAttrs(component, key, value, componentList);
-    }
-
-    private static void closestByAttrs(WXComponent component, String key, String value, List<WXComponent> componentList){
-        if(matchAttrs(component, key, value)){
-            componentList.add(component);
-        }
-        if(component instanceof  WXCell || component instanceof  WXRecyclerTemplateList){
-            return;
-        }
-        queryElementAllByAttrs(component.getParent(), key, value, componentList);
-    }
-
-
-    private static void queryElementAllByAttrs(WXComponent component, String key, String value, List<WXComponent> componentList){
-        if(matchAttrs(component, key, value)){
-            componentList.add(component);
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            for(int i=0; i<container.getChildCount(); i++){
-                queryElementAllByAttrs(container.getChild(i), key, value, componentList);
-            }
-        }
-    }
-
-
-    private static boolean matchAttrs(WXComponent component, String key, String value){
-        if(component.isWaste()){
-            return false;
-        }
-        if(!component.getAttrs().containsKey(key)){
-            return false;
-        }
-        if(TextUtils.isEmpty(value)){
-            return true;
-        }
-        Object attrValue = component.getAttrs().get(key);
-        if(attrValue == null){
-            return false;
-        }
-        return value.equals(attrValue.toString());
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateCache.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateCache.java
deleted file mode 100644
index 4ae98c3..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateCache.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import com.taobao.weex.ui.component.list.WXCell;
-
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * preload cell cache
- * Created by furture on 2017/9/29.
- */
-class TemplateCache {
-    ConcurrentLinkedQueue<WXCell> cells = new ConcurrentLinkedQueue<>();
-    boolean isLoadIng = false;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateDom.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateDom.java
deleted file mode 100644
index 78f7d90..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateDom.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by furture on 2018/6/27.
- */
-
-public class TemplateDom {
-
-    public static final String KEY_RESET_ANIMATION = "resetAnimation";
-    public static final String KEY_ATTRS = "attrs";
-    public static final String KEY_TYPE = "type";
-    public static final String KEY_VIRTUAL_DOM_REF = "ref";
-    public static final String VIRTUAL_DOM_IDENTIFY = "[[VirtualElement]]";
-
-
-    public static final String ATTRS_KEY_REF = "ref";
-
-    public static final String ATTACH_CELL_SLOT = "_attach_slot";
-    public static final String DETACH_CELL_SLOT = "_detach_slot";
-
-    public static final char SEPARATOR = '@';
-
-
-    public static String genKeyVirtualDomRef(String listRef, int position, String key){
-        return listRef + SEPARATOR + position + SEPARATOR  +  key;
-    }
-
-    public static WXComponent findVirtualComponentByVRef(String pageId, String virtualRef) {
-        try{
-
-            String[]  segments = virtualRef.split(SEPARATOR + "");
-            String listRef = segments[0]; // list ref
-            WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(pageId, listRef);
-            if(!(component instanceof WXRecyclerTemplateList)){
-                return null;
-            }
-            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) component;
-            if(templateList.getHostView() == null || templateList.getHostView().getInnerView() == null){
-                return null;
-            }
-            int position = Integer.parseInt(segments[1]); // position
-            WXRecyclerView recyclerView = templateList.getHostView().getInnerView();
-            TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(position);
-            if(itemHolder == null){
-                return null;
-            }
-
-            WXCell cell = itemHolder.getTemplate();
-            String viewKey = segments[2]; //viewkey
-            WXComponent target = findComponentByViewTreeKey(cell, viewKey);
-            return  target;
-        }catch (Exception e){
-            return  null;
-        }
-    }
-
-    /**
-     * find all component that contains ref attr
-     * */
-    public static Map<String,Object> findAllComponentRefs(String listRef, int position , WXComponent component){
-        Map<String,Object> refs = new HashMap<>();
-        findAllComponentRefs(listRef, position, component, refs);
-        Map<String,Object> refsMap = new HashMap<>();
-        refsMap.put("refs", refs);
-        refsMap.put("position", position);
-        refsMap.put("listRef", listRef);
-        return refsMap;
-    }
-
-    private static void findAllComponentRefs(String listRef, int position, WXComponent component, Map<String,Object> refs){
-        if(component.isWaste()){
-            return;
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            for(int i=0; i<container.getChildCount(); i++){
-                WXComponent child = container.getChild(i);
-                findAllComponentRefs(listRef, position, child, refs);
-            }
-        }
-        WXAttr attrs = component.getAttrs();
-        if(attrs != null
-                && attrs.get(TemplateDom.ATTRS_KEY_REF) == null){
-            return;
-        }
-        String ref  = attrs.get(TemplateDom.ATTRS_KEY_REF).toString();
-        List<Object> refList = (List<Object>) refs.get(ref);
-        if(refList == null){
-            refList = new ArrayList<>();
-            refs.put(ref, refList);
-        }
-        Map map = toMap(listRef, position, component);
-        refList.add(map);
-    }
-
-
-    public static Map toMap(String listRef, int position, WXComponent component){
-        Map map = new HashMap();
-        map.put(TemplateDom.KEY_ATTRS, component.getAttrs());
-        map.put(TemplateDom.KEY_TYPE, component.getComponentType());
-        map.put(TemplateDom.KEY_VIRTUAL_DOM_REF, TemplateDom.genKeyVirtualDomRef(listRef, position, component.getViewTreeKey()));
-        map.put(VIRTUAL_DOM_IDENTIFY, true);
-        return map;
-    }
-
-
-    public static boolean isVirtualDomRef(String ref){
-        if(ref != null){
-            return  ref.indexOf(SEPARATOR) > 0;
-        }
-        return  false;
-    }
-
-
-    public static void resetAnimaiton(View view){
-        if(view == null){
-            return;
-        }
-        if(ViewCompat.getTranslationX(view) != 0){
-            ViewCompat.setTranslationX(view, 0);
-        }
-
-        if(ViewCompat.getTranslationY(view) != 0){
-            ViewCompat.setTranslationY(view, 0);
-        }
-
-        if(ViewCompat.getTranslationZ(view) != 0){
-            ViewCompat.setTranslationZ(view, 0);
-        }
-
-        if(ViewCompat.getScaleX(view) != 1.0f){
-            ViewCompat.setScaleX(view, 1.0f);
-        }
-
-        if(ViewCompat.getScaleY(view) != 1.0f){
-            ViewCompat.setScaleY(view, 1.0f);
-        }
-
-        if(ViewCompat.getRotationX(view) != 0){
-            ViewCompat.setRotationX(view, 0);
-        }
-
-        if(ViewCompat.getRotationY(view) != 0){
-            ViewCompat.setRotationY(view, 0);
-        }
-
-        if(ViewCompat.getElevation(view) != 0){
-            ViewCompat.setElevation(view, 0);
-        }
-    }
-
-
-    /**
-     * find child list, has same ref
-     * */
-    public static final  WXComponent findComponentByViewTreeKey(WXComponent component, String viewKey){
-        if(component.getViewTreeKey().equals(viewKey)){
-            return component;
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            for(int i=0; i<container.getChildCount(); i++){
-                WXComponent element = container.getChild(i);
-                if(findComponentByViewTreeKey(element, viewKey) != null){
-                    return element;
-                }
-            }
-
-        }
-        return null;
-    }
-
-    /**
-     * find child by ref
-     * */
-    private  static WXComponent findChildByAttrsRef(WXComponent component, String ref){
-        if(component.getAttrs() != null && ref.equals(component.getAttrs().get(TemplateDom.ATTRS_KEY_REF))){
-            return component;
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            for(int i=0; i<container.getChildCount(); i++){
-                WXComponent child = findChildByAttrsRef(container.getChild(i), ref);
-                if(child != null){
-                    return  child;
-                }
-            }
-        }
-        return  null;
-    }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateStickyHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateStickyHelper.java
deleted file mode 100644
index ffc6b07..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateStickyHelper.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import android.support.v4.util.ArrayMap;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.view.refresh.wrapper.BounceRecyclerView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * StickyHelper For Template List
- * Created by furture on 2017/8/24.
- */
-public class TemplateStickyHelper {
-    private WXRecyclerTemplateList recyclerTemplateList;
-    private List<Integer> stickyPositions;
-    private ArrayMap<Integer, TemplateViewHolder>   stickyHolderCache;
-    private List<String> mStickyTypes;
-
-
-    public TemplateStickyHelper(WXRecyclerTemplateList recyclerTemplateList) {
-        this.recyclerTemplateList = recyclerTemplateList;
-        this.stickyPositions = new ArrayList<>();
-        this.stickyHolderCache = new ArrayMap();
-        this.mStickyTypes = new ArrayList<>(8);
-    }
-
-    /**
-     * dispatch scroll event, sticky  header
-     * */
-    public void onBeforeScroll(int dx, int dy) {
-        if(stickyPositions == null || stickyPositions.size() == 0){
-           return;
-        }
-        BounceRecyclerView bounceRecyclerView = recyclerTemplateList.getHostView();
-        RecyclerView recyclerView = recyclerTemplateList.getHostView().getInnerView();
-        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-        int firstVisiblePosition = -1;
-        int lastVisiblePosition = -1;
-        if (layoutManager instanceof LinearLayoutManager) {
-            firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
-            lastVisiblePosition  = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
-        }else if (layoutManager instanceof StaggeredGridLayoutManager) {
-            int [] firstVisibleItemPositions = new int[3];//max 3 column
-            firstVisiblePosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(firstVisibleItemPositions)[0];
-            lastVisiblePosition = ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(firstVisibleItemPositions)[0];
-        }
-        if(firstVisiblePosition < 0){
-            return;
-        }
-
-        TemplateViewHolder firstVisibleItemHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(firstVisiblePosition);
-        if(firstVisibleItemHolder == null){
-            return;
-        }
-
-        //find match sticky position
-        int matchStickyPosition = -1;
-        for (Integer headerPosition : stickyPositions){
-            if(headerPosition == null){
-                continue;
-            }
-            if(headerPosition <= firstVisiblePosition){
-                matchStickyPosition = Math.max(matchStickyPosition, headerPosition);
-            }else{
-                break;
-            }
-        }
-        if(matchStickyPosition < 0){
-            //remove holder for match position not found
-            View stickyFakeView = bounceRecyclerView.getChildAt(bounceRecyclerView.getChildCount() - 1);
-            if(stickyFakeView.getTag() instanceof TemplateViewHolder){
-                TemplateViewHolder stickyFakeViewHolder = (TemplateViewHolder) stickyFakeView.getTag();
-                bounceRecyclerView.removeView(stickyFakeViewHolder.itemView);
-                stickyFakeViewHolder.itemView.setTranslationY(0);
-                if(stickyFakeViewHolder.getComponent() != null
-                        && stickyFakeViewHolder.getComponent().getEvents().contains(Constants.Event.UNSTICKY)){
-                    stickyFakeViewHolder.getComponent().fireEvent(Constants.Event.UNSTICKY);
-                }
-            }
-
-            /**check has sticky cell not visible */
-            for(int i=0; i<recyclerView.getChildCount(); i++) {
-                View itemView = recyclerView.getChildAt(i);
-                TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.getChildViewHolder(itemView);
-                if (itemHolder == null) {
-                    continue;
-                }
-                int adapterPosition = itemHolder.getAdapterPosition();
-                if (!stickyPositions.contains(adapterPosition)) {
-                    continue;
-                }
-                if(itemView.getVisibility() != View.VISIBLE) {
-                    itemView.setVisibility(View.VISIBLE);
-                }
-            }
-            return;
-        }
-
-        //onCreate holder for match position if not exist
-        View stickyFakeView = bounceRecyclerView.getChildAt(bounceRecyclerView.getChildCount() - 1);
-        if(!(stickyFakeView.getTag() instanceof TemplateViewHolder)
-                || ((TemplateViewHolder) stickyFakeView.getTag()).getHolderPosition() != matchStickyPosition){
-
-             //remove previous sticky header
-            if(stickyFakeView.getTag() instanceof TemplateViewHolder &&
-                    ((TemplateViewHolder) stickyFakeView.getTag()).getHolderPosition() != matchStickyPosition){
-                TemplateViewHolder stickyFakeViewHolder = (TemplateViewHolder) stickyFakeView.getTag();
-                bounceRecyclerView.removeView(stickyFakeViewHolder.itemView);
-                stickyFakeViewHolder.itemView.setTranslationY(0);
-                if(stickyFakeViewHolder.getComponent() != null
-                        && stickyFakeViewHolder.getComponent().getEvents().contains(Constants.Event.UNSTICKY)){
-                    stickyFakeViewHolder.getComponent().fireEvent(Constants.Event.UNSTICKY);
-                }
-            }
-
-            //onCreate new sticky
-            int stickyHolderType = recyclerTemplateList.getItemViewType(matchStickyPosition);
-            TemplateViewHolder fakeStickyHolder = stickyHolderCache.get(stickyHolderType);
-            if(fakeStickyHolder == null){
-                fakeStickyHolder = recyclerTemplateList.onCreateViewHolder(recyclerView, stickyHolderType);
-                stickyHolderCache.put(stickyHolderType, fakeStickyHolder);
-            }
-            recyclerTemplateList.onBindViewHolder(fakeStickyHolder, matchStickyPosition);
-            fakeStickyHolder.itemView.setTranslationY(0);
-            fakeStickyHolder.itemView.setTag(fakeStickyHolder);
-            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-            fakeStickyHolder.getComponent().clearPreLayout();
-            if(fakeStickyHolder.itemView.getParent() != null){
-                ViewGroup parent = (ViewGroup) fakeStickyHolder.itemView.getParent();
-                parent.removeView(fakeStickyHolder.itemView);
-            }
-            bounceRecyclerView.addView(fakeStickyHolder.itemView, params);
-            fakeStickyHolder.getComponent().setLayout(fakeStickyHolder.getComponent());
-            stickyFakeView = fakeStickyHolder.itemView;
-            if(fakeStickyHolder.getComponent() != null
-                    && fakeStickyHolder.getComponent().getEvents().contains(Constants.Event.STICKY)){
-                fakeStickyHolder.getComponent().fireEvent(Constants.Event.STICKY);
-            }
-        }
-        TemplateViewHolder stickyFakeViewHolder = (TemplateViewHolder) stickyFakeView.getTag();
-        for(int i=0; i<recyclerView.getChildCount(); i++){
-            View itemView = recyclerView.getChildAt(i);
-            TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.getChildViewHolder(itemView);
-            if(itemHolder == null){
-                continue;
-            }
-            int adapterPosition = itemHolder.getAdapterPosition();
-            if(!stickyPositions.contains(adapterPosition)){
-                continue;
-            }
-            if(adapterPosition == stickyFakeViewHolder.getHolderPosition()){
-                if(itemView.getVisibility() != View.INVISIBLE) {
-                    itemView.setVisibility(View.INVISIBLE);
-                }
-            }else{
-                if(itemView.getVisibility() != View.VISIBLE) {
-                    itemView.setVisibility(View.VISIBLE);
-                }
-            }
-        }
-
-        if(firstVisibleItemHolder.getComponent().isSticky()){
-            if(firstVisibleItemHolder.itemView.getY() < 0){
-                if(firstVisibleItemHolder.itemView.getVisibility() != View.INVISIBLE) {
-                    firstVisibleItemHolder.itemView.setVisibility(View.INVISIBLE);
-                }
-                if(stickyFakeView.getVisibility() != View.VISIBLE) {
-                    stickyFakeView.setVisibility(View.VISIBLE);
-                }
-                stickyFakeView.bringToFront();
-            }else{
-                if(firstVisibleItemHolder.itemView.getVisibility() != View.VISIBLE) {
-                    firstVisibleItemHolder.itemView.setVisibility(View.VISIBLE);
-                }
-                if(stickyFakeView.getVisibility() != View.GONE) {
-                    stickyFakeView.setVisibility(View.GONE);
-                }
-            }
-        }else{
-            if(stickyFakeView.getVisibility() != View.VISIBLE){
-                stickyFakeView.setVisibility(View.VISIBLE);
-            }
-        }
-
-        //handle sticky is related, find next sticky position on screen
-        int nextVisiblePostion = firstVisiblePosition + 1;
-        if(lastVisiblePosition > 0){
-            for(int i=nextVisiblePostion; i<= lastVisiblePosition; i++){
-                if(stickyPositions.contains(i)){
-                    nextVisiblePostion = i;
-                    break;
-                }
-            }
-        }
-        if(!stickyPositions.contains(nextVisiblePostion)){
-            if(stickyFakeViewHolder.itemView.getTranslationY() < 0){
-                stickyFakeViewHolder.itemView.setTranslationY(0);
-            }
-            return;
-        }
-        TemplateViewHolder nextStickyHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(nextVisiblePostion);
-        if(nextStickyHolder == null
-                || nextStickyHolder.getComponent() == null){
-            return;
-        }
-        int translationY = (int)(nextStickyHolder.itemView.getY() - stickyFakeViewHolder.itemView.getMeasuredHeight());
-        if(translationY <= 0){
-            stickyFakeViewHolder.itemView.setTranslationY(translationY);
-        }else{
-            stickyFakeViewHolder.itemView.setTranslationY(0);
-        }
-    }
-
-    public List<Integer> getStickyPositions() {
-        if(stickyPositions == null){
-            stickyPositions = new ArrayList<>();
-        }
-        return stickyPositions;
-    }
-
-    public List<String> getStickyTypes() {
-        return mStickyTypes;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java
deleted file mode 100644
index c0d4fb0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import android.os.AsyncTask;
-import android.view.View;
-
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.view.listview.adapter.ListBaseViewHolder;
-
-/**
- * Created by furture on 2017/8/17.
- */
-
-public class TemplateViewHolder extends ListBaseViewHolder {
-
-    /**
-     * strong reference, prevent recycled
-     * */
-    private WXCell template;
-
-    private WXRecyclerTemplateList templateList;
-
-    private int holderPosition = -1;
-
-    public AsyncTask<Void, Void, Void> asyncTask;
-
-    public Object  data;
-
-    /**
-     * header position
-     * */
-
-    public TemplateViewHolder(WXRecyclerTemplateList templateList, WXCell component, int viewType) {
-        super(component, viewType);
-        this.template = component;
-        this.templateList = templateList;
-    }
-
-    public TemplateViewHolder(WXRecyclerTemplateList templateList, View view, int viewType) {
-        super(view, viewType);
-        this.templateList = templateList;
-    }
-
-
-
-
-    public int getHolderPosition() {
-        return holderPosition;
-    }
-
-    public void setHolderPosition(int holderPosition) {
-        this.holderPosition = holderPosition;
-    }
-
-    public WXCell getTemplate() {
-        return template;
-    }
-
-    public WXRecyclerTemplateList getTemplateList() {
-        return templateList;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/VirtualComponentLifecycle.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/VirtualComponentLifecycle.java
deleted file mode 100644
index 5466621..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/VirtualComponentLifecycle.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-
-/**
- * Created by furture on 2018/2/1.
- */
-
-public class VirtualComponentLifecycle {
-
-    /**
-     * lifecycle
-     * */
-    public static final  String LIFECYCLE = "lifecycle";
-
-
-    /**
-     * virtual component lifecycle
-     * */
-    public static final  String CREATE = "create";
-
-    public static final  String ATTACH = "attach";
-
-    public static final  String SYNSTATE = "syncState";
-
-    public static final  String DETACH = "detach";
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
deleted file mode 100644
index 33f6de6..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
+++ /dev/null
@@ -1,2019 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template;
-
-import static com.taobao.weex.common.Constants.Name.LOADMOREOFFSET;
-import static com.taobao.weex.ui.view.listview.WXRecyclerView.TYPE_LINEAR_LAYOUT;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.os.Build;
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.annotation.Component;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.ICheckBindingScroller;
-import com.taobao.weex.common.OnWXScrollListener;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.el.parse.ArrayStack;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.AppearanceHelper;
-import com.taobao.weex.ui.component.Scrollable;
-import com.taobao.weex.ui.component.WXBaseRefresh;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXComponentProp;
-import com.taobao.weex.ui.component.WXLoading;
-import com.taobao.weex.ui.component.WXRefresh;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.component.binding.Layouts;
-import com.taobao.weex.ui.component.binding.Statements;
-import com.taobao.weex.ui.component.helper.ScrollStartEndHelper;
-import com.taobao.weex.ui.component.list.RecyclerTransform;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-import com.taobao.weex.ui.view.listview.adapter.IOnLoadMoreListener;
-import com.taobao.weex.ui.view.listview.adapter.IRecyclerAdapterListener;
-import com.taobao.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
-import com.taobao.weex.ui.view.listview.adapter.WXRecyclerViewOnScrollListener;
-import com.taobao.weex.ui.view.refresh.wrapper.BounceRecyclerView;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * weex template list supported, high performance recycler-list
- * https://github.com/Hanks10100/weex-native-directive
- * Created by jianbai.gbj on 2017/8/17.
- */
-@Component(lazyload = false)
-public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> implements
-        IRecyclerAdapterListener<TemplateViewHolder>, IOnLoadMoreListener, Scrollable {
-
-    /**
-     * trace log for template list
-     * */
-    public static final boolean ENABLE_TRACE_LOG = false;
-
-    public static final String TAG = "WXRecyclerTemplateList";
-
-    private static final String EMPTY_HOLDER_TEMPLATE_KEY  = "";
-    private static final String NAME_HAS_FIXED_SIZE = "hasFixedSize";
-    private static final String NAME_ITEM_VIEW_CACHE_SIZE = "itemViewCacheSize";
-    private static final String NAME_TEMPLATE_CACHE_SIZE = "templateCacheSize";
-
-    // TODO
-//    private WXRecyclerDomObject mDomObject;
-    protected int mLayoutType = TYPE_LINEAR_LAYOUT;
-    protected int mColumnCount = 1;
-    protected float mColumnGap = 0;
-    protected float mColumnWidth = 0;
-    private float mPaddingLeft;
-    private float mPaddingRight;
-
-    private WXRecyclerViewOnScrollListener mViewOnScrollListener = new WXRecyclerViewOnScrollListener(this);
-    private int mListCellCount = 0;
-    private boolean mForceLoadmoreNextTime = false;
-    private RecyclerView.ItemAnimator mItemAnimator;
-
-    /**
-     * default orientation
-     * */
-    private  int orientation = Constants.Orientation.VERTICAL;
-
-    /**
-     * offset reported
-     * */
-    private boolean isScrollable = true;
-    private int mOffsetAccuracy = 10;
-    private Point mLastReport = new Point(-1, -1);
-    private boolean mHasAddScrollEvent = false;
-
-
-    private CellDataManager cellDataManager;
-    private String listDataKey = Constants.Name.Recycler.LIST_DATA;
-    private String listDataItemKey = null;
-    private String listDataIndexKey = null;
-    private ArrayMap<String, Integer> mTemplateViewTypes;
-
-
-    private Map<String, WXCell> mTemplateSources;
-    private String  listDataTemplateKey = Constants.Name.Recycler.SLOT_TEMPLATE_CASE;
-    private Runnable listUpdateRunnable;
-    private ConcurrentHashMap<String, TemplateCache> mTemplatesCache;
-    private int templateCacheSize = 2;
-
-
-    /**
-     * case default cell and key
-     * */
-    private WXCell defaultTemplateCell;
-    private String defaultTemplateKey = "@default_template_cell";
-
-    /**
-     * scroll start and scroll end event
-     * */
-    private ScrollStartEndHelper mScrollStartEndHelper;
-
-
-    /**
-     * sticky helper
-     * */
-    private TemplateStickyHelper mStickyHelper;
-
-
-    /**
-     * appear and disappear event managaer
-     * */
-    private ArrayMap<Integer, List<AppearanceHelper>> mAppearHelpers = new ArrayMap<>();
-
-    /**
-     * disappear event will be fire,
-     * fist layer map key position,
-     * send layer map key String ref
-     * three layer map key view hash code, value is event arguments
-     * */
-    private ArrayMap<Integer, Map<String,Map<Integer, List<Object>>>> mDisAppearWatchList = new ArrayMap<>();
-
-    private CellRenderContext cellRenderContext = new CellRenderContext();
-
-    private Runnable mAppearChangeRunnable = null;
-    private static final long APPEAR_CHANGE_RUNNABLE_DELAY = 50;
-
-    /**
-     * has append tree done
-     * */
-    private boolean hasAppendTreeDone = false;
-
-    /**
-     * has layout done
-     * */
-    private boolean hasLayoutDone = false;
-
-    public WXRecyclerTemplateList(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-        super(instance, parent, basicComponentData);
-        initRecyclerTemplateList(instance, basicComponentData, parent);
-    }
-
-    private void initRecyclerTemplateList(WXSDKInstance instance, BasicComponentData basicComponentData,
-                                          WXVContainer parent){
-
-        updateRecyclerAttr();
-
-        mTemplateViewTypes = new ArrayMap<>();
-        mTemplateViewTypes.put(EMPTY_HOLDER_TEMPLATE_KEY, 0); //empty view, when template was not sended
-        mTemplateSources = new HashMap<>();
-        mTemplatesCache = new ConcurrentHashMap<>();
-        mStickyHelper = new TemplateStickyHelper(this);
-        orientation =  basicComponentData.getAttrs().getOrientation();
-        listDataTemplateKey = WXUtils.getString(getAttrs().get(Constants.Name.Recycler.LIST_DATA_TEMPLATE_SWITCH_KEY), Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
-        listDataItemKey = WXUtils.getString(getAttrs().get(Constants.Name.Recycler.LIST_DATA_ITEM), listDataItemKey);
-        listDataIndexKey = WXUtils.getString(getAttrs().get(Constants.Name.Recycler.LIST_DATA_ITEM_INDEX), listDataIndexKey);
-        cellDataManager = new CellDataManager(this);
-        cellDataManager.listData = parseListDataToJSONArray(getAttrs().get(Constants.Name.Recycler.LIST_DATA));
-        /**
-         * we have separate cell with list, post add cell in dom thread ensure
-         * list has layout and can archive better user experience and better load time,
-         * which reduce waste cell layout when list layout changes.
-         * */
-        // TODO
-//        if(mDomObject != null
-//                && mDomObject.getCellList() != null
-//                && mDomObject.getCellList().size() > 0){
-//            Runnable runnable =  new Runnable() {
-//                // @Override
-//                public void run() {
-//                    if(isDestoryed()){
-//                        return;
-//                    }
-//                    long start = System.currentTimeMillis();
-//                    if(mDomObject != null && mDomObject.getCellList() != null){
-//                        for(int i=0; i<mDomObject.getCellList().size(); i++){
-//                            addChild(ComponentUtils.buildTree(mDomObject.getCellList().get(i),  WXRecyclerTemplateList.this));
-//                        }
-//                    }
-//                    if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
-//                        WXLogUtils.d(TAG, "TemplateList BuildDomTree Used " + (System.currentTimeMillis() - start));
-//                    }
-//                }
-//            };
-//            WXSDKManager.getInstance().getWXDomManager().post(runnable);
-//        }
-    }
-
-    @Override
-    protected BounceRecyclerView initComponentHostView(@NonNull Context context) {
-        final BounceRecyclerView bounceRecyclerView = new BounceRecyclerView(context,mLayoutType,mColumnCount,mColumnGap, getOrientation());
-        WXAttr attrs = getAttrs();
-        String transforms = (String) attrs.get(Constants.Name.TRANSFORM);
-        if (transforms != null) {
-            bounceRecyclerView.getInnerView().addItemDecoration(RecyclerTransform.parseTransforms(getOrientation(), transforms));
-        }
-        mItemAnimator = bounceRecyclerView.getInnerView().getItemAnimator();
-
-        if(attrs.get(NAME_TEMPLATE_CACHE_SIZE) != null){
-            templateCacheSize =  WXUtils.getInteger(attrs.get(NAME_TEMPLATE_CACHE_SIZE), templateCacheSize);
-        }
-
-        boolean hasFixedSize = false;
-        int itemViewCacheSize = 2;
-        if(attrs.get(NAME_ITEM_VIEW_CACHE_SIZE) != null){
-            itemViewCacheSize = WXUtils.getNumberInt(getAttrs().get(NAME_ITEM_VIEW_CACHE_SIZE), itemViewCacheSize);
-        }
-        if(attrs.get(NAME_HAS_FIXED_SIZE) != null){
-            hasFixedSize =  WXUtils.getBoolean(attrs.get(NAME_HAS_FIXED_SIZE), hasFixedSize);
-        }
-        RecyclerViewBaseAdapter recyclerViewBaseAdapter = new RecyclerViewBaseAdapter<>(this);
-        recyclerViewBaseAdapter.setHasStableIds(true);
-        bounceRecyclerView.getInnerView().setItemAnimator(null);
-        if(itemViewCacheSize != 2) {
-            bounceRecyclerView.getInnerView().setItemViewCacheSize(itemViewCacheSize);
-        }
-        if(bounceRecyclerView.getSwipeLayout()  != null){
-            if(WXUtils.getBoolean(getAttrs().get("nestedScrollingEnabled"), false)) {
-                bounceRecyclerView.getSwipeLayout().setNestedScrollingEnabled(true);
-            }
-        }
-        bounceRecyclerView.getInnerView().setHasFixedSize(hasFixedSize);
-        bounceRecyclerView.setRecyclerViewBaseAdapter(recyclerViewBaseAdapter);
-        bounceRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
-        bounceRecyclerView.getInnerView().clearOnScrollListeners();
-        bounceRecyclerView.getInnerView().addOnScrollListener(mViewOnScrollListener);
-        bounceRecyclerView.getInnerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                super.onScrollStateChanged(recyclerView, newState);
-                getScrollStartEndHelper().onScrollStateChanged(newState);
-                List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
-                if (listeners != null && listeners.size() > 0) {
-                    for (OnWXScrollListener listener : listeners) {
-                        if (listener != null) {
-                            View topView = recyclerView.getChildAt(0);
-                            if (topView != null) {
-                                int y = topView.getTop();
-                                listener.onScrollStateChanged(recyclerView, 0, y, newState);
-                            }
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                super.onScrolled(recyclerView, dx, dy);
-                List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
-                if (listeners != null && listeners.size() > 0) {
-                    try {
-                        for (OnWXScrollListener listener : listeners) {
-                            if (listener != null) {
-                                if (listener instanceof ICheckBindingScroller) {
-                                    if (((ICheckBindingScroller) listener).isNeedScroller(getRef(), null)) {
-                                        listener.onScrolled(recyclerView, dx, dy);
-                                    }
-                                } else {
-                                    listener.onScrolled(recyclerView, dx, dy);
-                                }
-                            }
-                        }
-                    } catch (Exception e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-        });
-        bounceRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
-            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-            @Override
-            public void onGlobalLayout() {
-                BounceRecyclerView view;
-                if ((view = getHostView()) == null)
-                    return;
-                mViewOnScrollListener.onScrolled(view.getInnerView(), 0, 0);
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-                    view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                } else {
-                    view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
-                }
-            }
-        });
-        listUpdateRunnable = new Runnable() {
-            @Override
-            public void run() {
-                /**
-                 * compute sticky position
-                 * */
-                if(mStickyHelper != null){
-                    if(mStickyHelper.getStickyTypes().size() > 0){
-                        mStickyHelper.getStickyPositions().clear();
-                        if(cellDataManager.listData != null){
-                            for(int i = 0; i< cellDataManager.listData.size(); i++){
-                                WXCell cell = getSourceTemplate(i);
-                                if(cell == null){
-                                    continue;
-                                }
-                                if(cell.isSticky()){
-                                    mStickyHelper.getStickyPositions().add(i);
-                                }
-                            }
-                        }
-                    }
-                }
-                if(getHostView() != null && getHostView().getRecyclerViewBaseAdapter() != null){
-                    getHostView().getRecyclerViewBaseAdapter().notifyDataSetChanged();
-                }
-                if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
-                    WXLogUtils.d(TAG, "WXTemplateList notifyDataSetChanged");
-                }
-            }
-        };
-        return bounceRecyclerView;
-    }
-
-
-
-
-    @Override
-    protected void onHostViewInitialized(BounceRecyclerView host) {
-        super.onHostViewInitialized(host);
-        WXRecyclerView recyclerView = host.getInnerView();
-        if (recyclerView == null || recyclerView.getAdapter() == null) {
-            WXLogUtils.e(TAG, "RecyclerView is not found or Adapter is not bound");
-            return;
-        }
-    }
-
-    /**
-     * Measure the size of the recyclerView.
-     *
-     * @param width  the expected width
-     * @param height the expected height
-     * @return the result of measurement
-     */
-    @Override
-    protected MeasureOutput measure(int width, int height) {
-        int screenH = WXViewUtils.getScreenHeight(WXEnvironment.sApplication);
-        int weexH = WXViewUtils.getWeexHeight(getInstanceId());
-        int outHeight = height > (weexH >= screenH ? screenH : weexH) ? weexH - getAbsoluteY() : height;
-        return super.measure(width, outHeight);
-    }
-
-
-    @Override
-    public void bindStickStyle(WXComponent component) {
-        WXComponent template = findParentType(component, WXCell.class);
-        if(template == null){
-            return;
-        }
-        if(mStickyHelper == null){
-            return;
-        }
-        if(!mStickyHelper.getStickyTypes().contains(template.getRef())){
-            mStickyHelper.getStickyTypes().add(template.getRef());
-            notifyUpdateList();
-        }
-    }
-
-    @Override
-    public void unbindStickStyle(WXComponent component) {
-        WXComponent template = findParentType(component, WXCell.class);
-        if(template == null
-                || mStickyHelper == null){
-            return;
-        }
-        if(mStickyHelper.getStickyTypes().contains(template.getRef())){
-            mStickyHelper.getStickyTypes().remove(template.getRef());
-            notifyUpdateList();
-        }
-    }
-
-    private @Nullable
-    WXCell findCell(WXComponent component) {
-        if(component instanceof WXCell){
-            return (WXCell) component;
-        }
-        WXComponent parent;
-        if (component == null || (parent = component.getParent()) == null) {
-            return null;
-        }
-        return findCell(parent);
-    }
-
-    private void setAppearanceWatch(WXComponent component, int event, boolean enable) {
-        if(cellDataManager.listData == null
-                || mAppearHelpers == null
-                || TextUtils.isEmpty(component.getRef())){
-            return;
-        }
-        WXCell cell = findCell(component);
-        int type = getCellTemplateItemType(cell);
-        if(type < 0){
-            return;
-        }
-        List<AppearanceHelper>  mAppearListeners = mAppearHelpers.get(type);
-        if(mAppearListeners == null){
-            mAppearListeners = new ArrayList<>();
-            mAppearHelpers.put(type, mAppearListeners);
-        }
-        AppearanceHelper item = null;
-        for(AppearanceHelper mAppearListener : mAppearListeners){
-            if(component.getRef().equals(mAppearListener.getAwareChild().getRef())){
-                item = mAppearListener;
-                break;
-            }
-        }
-        if (item != null) {
-            item.setWatchEvent(event, enable);
-        }else {
-            item = new AppearanceHelper(component,  type);
-            item.setWatchEvent(event, enable);
-            mAppearListeners.add(item);
-        }
-    }
-
-    @Override
-    public void bindAppearEvent(WXComponent component) {
-        setAppearanceWatch(component, AppearanceHelper.APPEAR, true);
-        if(mAppearChangeRunnable == null){
-            mAppearChangeRunnable =  new Runnable() {
-                @Override
-                public void run() {
-                    if(mAppearChangeRunnable != null) {
-                        notifyAppearStateChange(0, 0, 0, 0);
-                    }
-                }
-            };
-        }
-        if (getHostView() != null) {
-            getHostView().removeCallbacks(mAppearChangeRunnable);
-            getHostView().postDelayed(mAppearChangeRunnable, APPEAR_CHANGE_RUNNABLE_DELAY);
-        }
-    }
-
-    @Override
-    public void bindDisappearEvent(WXComponent component) {
-        setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, true);
-        if(mAppearChangeRunnable == null){
-            mAppearChangeRunnable =  new Runnable() {
-                @Override
-                public void run() {
-                    if(mAppearChangeRunnable != null) {
-                        notifyAppearStateChange(0, 0, 0, 0);
-                    }
-                }
-            };
-        }
-        if (getHostView() != null) {
-            getHostView().removeCallbacks(mAppearChangeRunnable);
-            getHostView().postDelayed(mAppearChangeRunnable, APPEAR_CHANGE_RUNNABLE_DELAY);
-        }
-    }
-
-    @Override
-    public void unbindAppearEvent(WXComponent component) {
-        setAppearanceWatch(component, AppearanceHelper.APPEAR, false);
-    }
-
-    @Override
-    public void unbindDisappearEvent(WXComponent component) {
-        setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, false);
-    }
-
-
-    @JSMethod(uiThread = true)
-    public void queryElement(String virtualRef, String selector, JSCallback callback){
-        try{
-            String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
-            String listRef = segments[0];
-            int position = Integer.parseInt(segments[1]); // position
-            WXComponent component = TemplateDom.findVirtualComponentByVRef(getInstanceId(), virtualRef);
-            if(component == null){
-                return;
-            }
-            if(getHostView() == null || getHostView().getInnerView() == null){
-                return;
-            }
-            List<WXComponent>  componentList  = new ArrayList<>(4);
-            Selector.queryElementAll(component, selector, componentList);
-            if(componentList.size() > 0){
-                callback.invoke(TemplateDom.toMap(listRef, position, componentList.get(0)));
-            }else{
-                callback.invoke(new HashMap<>(4));
-            }
-        }catch (Exception e){
-            callback.invoke(new HashMap<>(4));
-            WXLogUtils.e(TAG, e);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void queryElementAll(String virtualRef,  String selector, JSCallback callback){
-        List datas = new ArrayList();
-        try{
-            String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
-            String listRef = segments[0];
-            int position = Integer.parseInt(segments[1]); // position
-            WXComponent component = TemplateDom.findVirtualComponentByVRef(getInstanceId(), virtualRef);
-            if(component == null){
-                return;
-            }
-            if(getHostView() == null || getHostView().getInnerView() == null){
-                return;
-            }
-            List<WXComponent>  componentList  = new ArrayList<>(4);
-            Selector.queryElementAll(component, selector, componentList);
-            for(WXComponent child : componentList){
-                datas.add(TemplateDom.toMap(listRef, position, child));
-            }
-            callback.invoke(datas);
-        }catch (Exception e){
-            callback.invoke(datas);
-            WXLogUtils.e(TAG, e);
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void closest(String virtualRef,  String selector, JSCallback callback){
-        try{
-            String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
-            String listRef = segments[0];
-            int position = Integer.parseInt(segments[1]); // position
-            WXComponent component = TemplateDom.findVirtualComponentByVRef(getInstanceId(), virtualRef);
-            if(component == null){
-                return;
-            }
-            if(getHostView() == null || getHostView().getInnerView() == null){
-                return;
-            }
-            List<WXComponent>  componentList  = new ArrayList<>(4);
-            Selector.closest(component, selector, componentList);
-            if(componentList.size() > 0){
-                callback.invoke(TemplateDom.toMap(listRef, position, componentList.get(0)));
-            }else{
-                callback.invoke(new HashMap<>(4));
-            }
-        }catch (Exception e){
-            callback.invoke(new HashMap<>(4));
-            WXLogUtils.e(TAG, e);
-        }
-    }
-
-
-
-    @JSMethod(uiThread = true)
-    public void scrollToElement(String virtualRef, Map<String, Object> options){
-        scrollTo(virtualRef, options);
-    }
-
-
-    @JSMethod(uiThread = true)
-    public void scrollTo(String virtualRef, Map<String, Object> options){
-        int position = -1;
-        try{
-            if(virtualRef.indexOf(TemplateDom.SEPARATOR) > 0){
-                String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
-                position = Integer.parseInt(segments[0]);
-            }else{
-                position = (int) Float.parseFloat(virtualRef);
-            }
-            if (position >= 0) {
-                boolean smooth = true;
-                float offsetFloat = 0;
-                if(options != null) {
-                    smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
-                    String offsetStr = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
-                    smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
-                    if (offsetStr != null) {
-                        try {
-                            offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offsetStr), getInstance().getInstanceViewPortWidth());
-                        }catch (Exception e ){
-                            WXLogUtils.e("Float parseFloat error :"+e.getMessage());
-                        }
-                    }
-                }
-                final int offset = (int) offsetFloat;
-
-                final int pos = position;
-                BounceRecyclerView bounceRecyclerView = getHostView();
-                if (bounceRecyclerView == null) {
-                    return;
-                }
-                final WXRecyclerView view = bounceRecyclerView.getInnerView();
-                view.scrollTo(smooth, pos, offset, getOrientation());
-            }
-        }catch (Exception e){
-            WXLogUtils.e(TAG, e);
-        }
-    }
-
-
-    @Override
-    public void scrollTo(WXComponent component, Map<String, Object> options) {
-        float offsetFloat = 0;
-        boolean smooth = true;
-        int position = -1;
-        int typeIndex = -1;
-        if (options != null) {
-            String offsetStr = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
-            smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
-            if (offsetStr != null) {
-                try {
-                    offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offsetStr), getInstance().getInstanceViewPortWidth());
-                }catch (Exception e ){
-                    WXLogUtils.e("Float parseFloat error :"+e.getMessage());
-                }
-            }
-            position = WXUtils.getNumberInt(options.get(Constants.Name.Recycler.CELL_INDEX), -1);
-            typeIndex = WXUtils.getNumberInt(options.get(Constants.Name.Recycler.TYPE_INDEX), -1);
-        }
-        WXCell cell = findCell(component);
-        if(typeIndex >= 0){
-            if(cellDataManager.listData != null && component.getRef() != null){
-                int typePosition = 0;
-                for(int i = 0; i< cellDataManager.listData.size(); i++){
-                    WXCell template = getSourceTemplate(i);
-                    if(template == null){
-                        continue;
-                    }
-                    if(cell.getRef().equals(template.getRef())){
-                        typePosition ++;
-                    }
-                    if(typePosition > typeIndex){
-                        position = i;
-                        break;
-                    }
-                }
-                if(position < 0){
-                    position = cellDataManager.listData.size() - 1;
-                }
-            }
-        }
-
-        final int offset = (int) offsetFloat;
-        BounceRecyclerView bounceRecyclerView = getHostView();
-        if (bounceRecyclerView == null) {
-            return;
-        }
-        if (position >= 0) {
-            final int pos = position;
-            final WXRecyclerView view = bounceRecyclerView.getInnerView();
-            view.scrollTo(smooth, pos, offset, getOrientation());
-        }
-    }
-
-    @Override
-    public int getScrollY() {
-        BounceRecyclerView bounceRecyclerView = getHostView();
-        return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollY();
-    }
-
-    @Override
-    public int getScrollX() {
-        BounceRecyclerView bounceRecyclerView = getHostView();
-        return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollX();
-    }
-
-    public int getOrientation() {
-        return orientation;
-    }
-
-    @Override
-    public boolean isScrollable() {
-        return isScrollable;
-    }
-
-
-
-    @Override
-    public void addChild(WXComponent child) {
-        this.addChild(child, -1);
-    }
-
-    @Override
-    protected int getChildrenLayoutTopOffset() {
-        return 0;
-    }
-
-    @Override
-    public void addChild(WXComponent child, int index) {
-        /**
-         *  dom object in component is not tree, build tree
-         * */
-        if(!(child instanceof WXCell)) {
-            super.addChild(child, index);
-        }
-        if(child instanceof WXBaseRefresh){
-            return;
-        }
-        if(child instanceof WXCell){
-            if(child.getAttrs() != null){
-                Object templateId = child.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
-                String key = WXUtils.getString(templateId, null);
-                if(getAttrs().containsKey(Constants.Name.Recycler.LIST_DATA_TEMPLATE_SWITCH_KEY)){
-                    if(defaultTemplateCell == null){
-                        defaultTemplateCell = (WXCell) child;
-                        if(!TextUtils.isEmpty(key)){
-                            defaultTemplateKey = key;
-                        }else{
-                            key = defaultTemplateKey;
-                            child.getAttrs().put(Constants.Name.Recycler.SLOT_TEMPLATE_CASE, key);
-                        }
-                    }
-                }else{
-                    if(defaultTemplateCell == null
-                            || child.getAttrs().containsKey(Constants.Name.Recycler.SLOT_TEMPLATE_DEFAULT)){
-                        defaultTemplateCell = (WXCell) child;
-                        if(!TextUtils.isEmpty(key)){
-                            defaultTemplateKey = key;
-                        }else{
-                            key = defaultTemplateKey;
-                            child.getAttrs().put(Constants.Name.Recycler.SLOT_TEMPLATE_CASE, key);
-                        }
-                    }
-                }
-                if(key != null){
-                    // TODO
-//                    if(child.getDomObject() instanceof  WXCellDomObject
-//                            && getDomObject() instanceof  WXRecyclerDomObject){
-//                        WXCellDomObject domObject = (WXCellDomObject) child.getDomObject();
-//                        domObject.setRecyclerDomObject((WXRecyclerDomObject) getDomObject());
-//                    }
-                    mTemplateSources.put(key, (WXCell) child);
-                    if(mTemplateViewTypes.get(key) == null){
-                        mTemplateViewTypes.put(key, mTemplateViewTypes.size());
-                    }
-                }
-            }
-
-            ((WXCell) child).setCellAppendTreeListener(new WXCell.CellAppendTreeListener() {
-                @Override
-                public void onAppendTreeDone() {
-                    checkAppendDone(false);
-                }
-            });
-        }
-    }
-
-
-    /**
-     * check all the cell has append tree done, then show list
-     * */
-    private void  checkAppendDone(boolean listDone){
-        if(mTemplateSources.size() == 0){
-            return;
-        }
-        Set<Map.Entry<String,WXCell>> cells = mTemplateSources.entrySet();
-        for(Map.Entry<String,WXCell> entry : cells){
-            if(!entry.getValue().isAppendTreeDone()){
-                return;
-            }
-        }
-        hasAppendTreeDone = true;
-        if(hasLayoutDone) {
-            notifyUpdateList();
-        }
-    }
-
-    @Override
-    protected void setHostLayoutParams(BounceRecyclerView host, int width, int height, int left, int right, int top, int bottom) {
-        super.setHostLayoutParams(host, width, height, left, right, top, bottom);
-        if(!hasLayoutDone){
-            hasLayoutDone = true;
-            hasAppendTreeDone = true;
-            notifyUpdateList();
-        }
-    }
-
-
-    /**
-     * RecyclerView manage its children in a way that different from {@link WXVContainer}. Therefore,
-     * {@link WXVContainer#addSubView(View, int)} is an empty implementation in {@link
-     * com.taobao.weex.ui.view.listview.WXRecyclerView}
-     */
-    @Override
-    public void addSubView(View child, int index) {
-
-    }
-
-
-    /**
-     * all child is template, none need onCreate child except loading and refresh.
-     * */
-    @Override
-    public void createChildViewAt(int index) {
-        int indexToCreate = index;
-        if (indexToCreate < 0) {
-            indexToCreate = childCount() - 1;
-            if (indexToCreate < 0) {
-                return;
-            }
-        }
-        final WXComponent child = getChild(indexToCreate);
-        if (child instanceof WXBaseRefresh) {
-            child.createView();
-            setRefreshOrLoading(child);
-        }
-    }
-
-    @Override
-    public void remove(WXComponent child, boolean destroy) {
-        removeFooterOrHeader(child);
-        super.remove(child, destroy);
-    }
-
-
-
-    @Override
-    public void computeVisiblePointInViewCoordinate(PointF pointF) {
-        RecyclerView view = getHostView().getInnerView();
-        pointF.set(view.computeHorizontalScrollOffset(), view.computeVerticalScrollOffset());
-    }
-
-    @Override
-    protected boolean setProperty(String key, Object param) {
-        switch (key) {
-            case Constants.Name.Recycler.LIST_DATA:{
-                     setListData(param);
-                }
-                return true;
-            case Constants.Name.Recycler.LIST_DATA_ITEM:
-                listDataItemKey = WXUtils.getString(param, listDataItemKey);
-                return true;
-            case Constants.Name.Recycler.LIST_DATA_ITEM_INDEX:
-                listDataIndexKey = WXUtils.getString(param, listDataIndexKey);
-                return true;
-            case Constants.Name.Recycler.LIST_DATA_TEMPLATE_SWITCH_KEY:
-            case Constants.Name.Recycler.SLOT_TEMPLATE_CASE:
-                listDataTemplateKey = WXUtils.getString(param, Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
-                return true;
-            case LOADMOREOFFSET:
-                return true;
-            case Constants.Name.SCROLLABLE:
-                boolean scrollable = WXUtils.getBoolean(param, true);
-                setScrollable(scrollable);
-                return true;
-            case Constants.Name.SCROLL_DIRECTION:
-                if(param != null) {
-                    setScrollDirection(param.toString());
-                }
-                return true;
-            case Constants.Name.SHOW_SCROLLBAR:
-                Boolean result = WXUtils.getBoolean(param,null);
-                if (result != null)
-                    setShowScrollbar(result);
-                return true;
-            case NAME_ITEM_VIEW_CACHE_SIZE:
-                return true;
-            case NAME_HAS_FIXED_SIZE:
-                return true;
-            case Constants.Name.OFFSET_ACCURACY:
-                int accuracy = WXUtils.getInteger(param, 10);
-                setOffsetAccuracy(accuracy);
-                return true;
-        }
-        return super.setProperty(key, param);
-    }
-
-
-    @WXComponentProp(name = Constants.Name.OFFSET_ACCURACY)
-    public void setOffsetAccuracy(int accuracy) {
-        float real = WXViewUtils.getRealPxByWidth(accuracy, getInstance().getInstanceViewPortWidth());
-        this.mOffsetAccuracy = (int) real;
-    }
-
-
-    private void updateRecyclerAttr(){
-        mLayoutType = getAttrs().getLayoutType();
-        mColumnCount = getAttrs().getColumnCount();
-        if (mColumnCount <= 0 && mLayoutType != TYPE_LINEAR_LAYOUT) {
-            Map<String, String> ext = new ArrayMap<>();
-            ext.put("componentType", getComponentType());
-            ext.put("attribute", getAttrs().toString());
-            ext.put("stackTrace", Arrays.toString(Thread.currentThread().getStackTrace()));
-            WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
-                WXErrorCode.WX_RENDER_ERR_LIST_INVALID_COLUMN_COUNT, "columnCount",
-                String.format(Locale.ENGLISH,
-                    "You are trying to set the list/recycler/vlist/waterfall's column to %d, which is illegal. The column count should be a positive integer",
-                    mColumnCount),
-                ext);
-            mColumnCount = Constants.Value.COLUMN_COUNT_NORMAL;
-        }
-        mColumnGap = getAttrs().getColumnGap();
-        mColumnWidth = getAttrs().getColumnWidth();
-        mPaddingLeft = getPadding().get(CSSShorthand.EDGE.LEFT);
-        mPaddingRight = getPadding().get(CSSShorthand.EDGE.RIGHT);
-
-    }
-
-
-    @WXComponentProp(name = Constants.Name.SCROLL_DIRECTION)
-    public void setScrollDirection(String direction){
-        if(orientation != getAttrs().getOrientation()) {
-            orientation = getAttrs().getOrientation();
-            updateRecyclerAttr();
-            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-            wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap, getOrientation());
-
-        }
-    }
-
-    @WXComponentProp(name = Constants.Name.COLUMN_WIDTH)
-    public void setColumnWidth(int columnCount)  {
-        if(getAttrs().getColumnWidth() != mColumnWidth){
-            updateRecyclerAttr();
-            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-            wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap, getOrientation());
-        }
-    }
-
-    @WXComponentProp(name = Constants.Name.SHOW_SCROLLBAR)
-    public void setShowScrollbar(boolean show) {
-        if(getHostView() == null || getHostView().getInnerView() == null){
-            return;
-        }
-        if (getOrientation() == Constants.Orientation.VERTICAL) {
-            getHostView().getInnerView().setVerticalScrollBarEnabled(show);
-        } else {
-            getHostView().getInnerView().setHorizontalScrollBarEnabled(show);
-        }
-    }
-
-    @WXComponentProp(name = Constants.Name.COLUMN_COUNT)
-    public void setColumnCount(int columnCount){
-        if(getAttrs().getColumnCount() != mColumnCount){
-            updateRecyclerAttr();
-            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-            wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
-        }
-    }
-
-    @WXComponentProp(name = Constants.Name.COLUMN_GAP)
-    public void setColumnGap(float columnGap) throws InterruptedException {
-        if(getAttrs().getColumnGap() != mColumnGap) {
-            updateRecyclerAttr();
-            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-            wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
-        }
-    }
-
-    @WXComponentProp(name = Constants.Name.SCROLLABLE)
-    public void setScrollable(boolean scrollable) {
-        WXRecyclerView inner = getHostView().getInnerView();
-        inner.setScrollable(scrollable);
-    }
-
-    @JSMethod
-    public void setListData(Object param){
-        param = parseListDataToJSONArray(param);
-        boolean update = cellDataManager.listData != param;
-        if(param instanceof  JSONArray){
-            if(update){
-                cellDataManager.setListData((JSONArray) param);
-                notifyUpdateList();
-            }
-        }
-    }
-
-    @JSMethod
-    public void  appendData(JSONArray data){
-        if(data == null || data.size() == 0){
-            return;
-        }
-        if(cellDataManager.listData == null){
-            cellDataManager.listData = new JSONArray();
-        }
-        int position = cellDataManager.listData.size();
-        if(position < 0){
-            position = 0;
-        }
-        if(data instanceof  JSONArray){
-            cellDataManager.listData.addAll(data);
-        }
-        getHostView().getRecyclerViewBaseAdapter().notifyItemRangeInserted(position, data.size());
-    }
-
-    @JSMethod
-    public void  insertData(int index, Object data){
-        if(data == null){
-            return;
-        }
-
-        if(cellDataManager.listData == null || index > cellDataManager.listData.size()){
-            return;
-        }
-        boolean renderStateChanged = cellDataManager.insertData(index, data);
-        if(renderStateChanged){
-            notifyUpdateList();
-        }else{
-            getHostView().getRecyclerViewBaseAdapter().notifyItemInserted(index);
-        }
-    }
-
-    @JSMethod
-    public void  appendRange(int index, JSONArray data){
-         insertRange(index, data);
-    }
-
-
-    /**
-     * when update data, list maybe contains sticky, may use position, when position changed should be rendered
-     * so use notifyUpdateList is better
-     * */
-
-    @JSMethod
-    public void  insertRange(int index, JSONArray data){
-        if(data == null || data.size() == 0){
-            return;
-        }
-        if(cellDataManager.listData == null || index > cellDataManager.listData.size()){
-            return;
-        }
-        boolean renderStateChange = cellDataManager.insertRange(index, data);
-        if(renderStateChange){
-            notifyUpdateList();
-        }else{
-            getHostView().getRecyclerViewBaseAdapter().notifyItemRangeInserted(index, data.size());
-        }
-
-    }
-
-    @JSMethod
-    public void  updateData(int index, Object data){
-        if(data == null){
-            return;
-        }
-        if(cellDataManager.listData == null || index >= cellDataManager.listData.size()){
-            return;
-        }
-        boolean onlyDataChange = cellDataManager.updateData(data, index);
-        if(onlyDataChange) {
-            getHostView().getRecyclerViewBaseAdapter().notifyItemChanged(index, data);
-        }else{
-            notifyUpdateList();
-        }
-    }
-
-    @JSMethod
-    public void  removeData(int index, int count){
-        if(cellDataManager.listData == null
-                || index >= cellDataManager.listData.size()){
-            return;
-        }
-        if(count <= 0){
-            count = 1;
-        }
-        int removeCount = 0;
-        while (count > 0 && index < cellDataManager.listData.size()){
-            cellDataManager.removeData(index);
-            count--;
-            removeCount++;
-        }
-        if(removeCount > 0) {
-            notifyUpdateList();
-        }
-    }
-
-
-    @JSMethod
-    public void resetLoadmore() {
-        mForceLoadmoreNextTime = true;
-        mListCellCount = 0;
-    }
-
-
-    @Override
-    public void updateProperties(Map<String, Object> props) {
-        super.updateProperties(props);
-        if(props.containsKey(Constants.Name.PADDING)
-                || props.containsKey(Constants.Name.PADDING_LEFT)
-                || props.containsKey(Constants.Name.PADDING_RIGHT)){
-
-            if(mPaddingLeft != getPadding().get(CSSShorthand.EDGE.LEFT)
-                    || mPaddingRight != getPadding().get(CSSShorthand.EDGE.RIGHT)) {
-                updateRecyclerAttr();
-                WXRecyclerView wxRecyclerView = getHostView().getInnerView();
-                wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
-            }
-        }
-    }
-
-
-
-    @Override
-    public void addEvent(String type) {
-        super.addEvent(type);
-        if (ScrollStartEndHelper.isScrollEvent(type)
-                && getHostView() != null
-                && getHostView().getInnerView() != null
-                && !mHasAddScrollEvent) {
-            mHasAddScrollEvent = true;
-            WXRecyclerView innerView = getHostView().getInnerView();
-            innerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-                private int offsetXCorrection, offsetYCorrection;
-                private boolean mFirstEvent = true;
-
-                @Override
-                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                    super.onScrolled(recyclerView, dx, dy);
-                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-                    if (!layoutManager.canScrollVertically()) {
-                        return;
-                    }
-                    int offsetX = recyclerView.computeHorizontalScrollOffset();
-                    int offsetY = recyclerView.computeVerticalScrollOffset();
-
-                    if (dx == 0 && dy == 0) {
-                        offsetXCorrection = offsetX;
-                        offsetYCorrection = offsetY;
-                        offsetX = 0;
-                        offsetY = 0;
-                    } else {
-                        offsetX = offsetX - offsetXCorrection;
-                        offsetY = offsetY - offsetYCorrection;
-                    }
-                    getScrollStartEndHelper().onScrolled(offsetX, offsetY);
-                    if(!getEvents().contains(Constants.Event.SCROLL)){
-                        return;
-                    }
-                    if (mFirstEvent) {
-                        //skip first event
-                        mFirstEvent = false;
-                        return;
-                    }
-
-                    if (shouldReport(offsetX, offsetY)) {
-                        fireScrollEvent(recyclerView, offsetX, offsetY);
-                    }
-                }
-            });
-        }
-    }
-
-    private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY) {
-        fireEvent(Constants.Event.SCROLL, getScrollEvent(recyclerView, offsetX, offsetY));
-    }
-
-    public Map<String, Object> getScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY){
-        offsetY = -calcContentOffset(recyclerView);
-        int contentWidth = recyclerView.getMeasuredWidth() + recyclerView.computeHorizontalScrollRange();
-        int contentHeight = calcContentSize();
-
-        Map<String, Object> event = new HashMap<>(3);
-        Map<String, Object> contentSize = new HashMap<>(3);
-        Map<String, Object> contentOffset = new HashMap<>(3);
-
-        contentSize.put(Constants.Name.WIDTH, WXViewUtils.getWebPxByWidth(contentWidth, getInstance().getInstanceViewPortWidth()));
-        contentSize.put(Constants.Name.HEIGHT, WXViewUtils.getWebPxByWidth(contentHeight, getInstance().getInstanceViewPortWidth()));
-
-        contentOffset.put(Constants.Name.X, - WXViewUtils.getWebPxByWidth(offsetX, getInstance().getInstanceViewPortWidth()));
-        contentOffset.put(Constants.Name.Y, - WXViewUtils.getWebPxByWidth(offsetY, getInstance().getInstanceViewPortWidth()));
-        event.put(Constants.Name.CONTENT_SIZE, contentSize);
-        event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
-        event.put(Constants.Name.ISDRAGGING, recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING);
-        return event;
-    }
-
-
-
-    private boolean shouldReport(int offsetX, int offsetY) {
-        if (mLastReport.x == -1 && mLastReport.y == -1) {
-            mLastReport.x = offsetX;
-            mLastReport.y = offsetY;
-            return true;
-        }
-
-        int gapX = Math.abs(mLastReport.x - offsetX);
-        int gapY = Math.abs(mLastReport.y - offsetY);
-
-        if (gapX >= mOffsetAccuracy || gapY >= mOffsetAccuracy) {
-            mLastReport.x = offsetX;
-            mLastReport.y = offsetY;
-            return true;
-        }
-
-        return false;
-    }
-
-
-    /**
-     * Setting refresh view and loading view
-     *
-     * @param child the refresh_view or loading_view
-     */
-    private boolean setRefreshOrLoading(final WXComponent child) {
-        if (child instanceof WXRefresh && getHostView() != null) {
-            getHostView().setOnRefreshListener((WXRefresh) child);
-            getHostView().postDelayed(WXThread.secure(new Runnable() {
-                @Override
-                public void run() {
-                    getHostView().setHeaderView(child);
-                }
-            }), 100);
-            return true;
-        }
-
-        if (child instanceof WXLoading && getHostView() != null) {
-            getHostView().setOnLoadingListener((WXLoading) child);
-            getHostView().postDelayed(WXThread.secure(new Runnable() {
-                @Override
-                public void run() {
-                    getHostView().setFooterView(child);
-                }
-            }), 100);
-            return true;
-        }
-        return false;
-    }
-
-
-    private void removeFooterOrHeader(WXComponent child) {
-        if (child instanceof WXLoading) {
-            getHostView().removeFooterView(child);
-        } else if (child instanceof WXRefresh) {
-            getHostView().removeHeaderView(child);
-        }
-    }
-
-    @Override
-    public ViewGroup.LayoutParams getChildLayoutParams(WXComponent child, View hostView, int width, int height, int left, int right, int top, int bottom) {
-        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) hostView.getLayoutParams();
-        if (child instanceof WXBaseRefresh && params == null) {
-            params = new LinearLayout.LayoutParams(width, height);
-        } else if (params == null) {
-            params = new RecyclerView.LayoutParams(width, height);
-        } else {
-            params.width = width;
-            params.height = height;
-
-            this.setMarginsSupportRTL(params, left, 0, right, 0);
-        }
-        return params;
-    }
-
-
-    @Override
-    public void destroy() {
-        synchronized (this){
-            if(getHostView() != null){
-                if(mAppearChangeRunnable != null) {
-                    getHostView().removeCallbacks(mAppearChangeRunnable);
-                    mAppearChangeRunnable = null;
-                }
-                getHostView().removeCallbacks(listUpdateRunnable);
-                if(getHostView().getInnerView() != null){
-                    getHostView().getInnerView().setAdapter(null);
-                }
-            }
-            if(cellDataManager.listData != null){
-                cellDataManager.setListData(null);
-            }
-            if(mStickyHelper != null){
-                mStickyHelper = null;
-            }
-            if(mTemplateViewTypes != null){
-                mTemplateViewTypes.clear();
-            }
-            if(mTemplateSources != null){
-                mTemplateSources.clear();
-            }
-            if(mAppearHelpers != null){
-                mAppearHelpers.clear();
-            }
-            if(mDisAppearWatchList != null){
-                mDisAppearWatchList.clear();
-            }
-            super.destroy();
-        }
-    }
-
-
-
-    @Override
-    public void onViewRecycled(TemplateViewHolder holder) {}
-
-    @Override
-    public void onBindViewHolder(final TemplateViewHolder templateViewHolder, int position) {
-        if(templateViewHolder == null){
-            return;
-        }
-        WXCell component = templateViewHolder.getTemplate();
-        if(component == null){
-            return;
-        }
-        if(templateViewHolder.getHolderPosition() >= 0){
-            fireEvent(TemplateDom.DETACH_CELL_SLOT, TemplateDom.findAllComponentRefs(getRef(), position, component));
-        }
-        long start = System.currentTimeMillis();
-        templateViewHolder.setHolderPosition(position);
-        Object data = cellDataManager.listData.get(position);
-        CellRenderState cellRenderState = cellDataManager.getRenderState(position);
-        if((component.getRenderData() == data && (cellRenderState == null || !cellRenderState.isDirty()))){
-            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
-                WXLogUtils.d(TAG,  position + " position "+ getTemplateKey(position) + " onBindViewHolder none data update "
-                        + " component " + component.hashCode());
-            }
-            fireEvent(TemplateDom.ATTACH_CELL_SLOT, TemplateDom.findAllComponentRefs(getRef(), position, component));
-            return;  //none update just return
-        }else{
-            List<WXComponent> updates = doRenderTemplate(component, position);
-            Statements.doInitCompontent(updates);
-            component.setRenderData(data);
-            Layouts.doLayoutAsync(templateViewHolder, true);
-            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
-                WXLogUtils.d(TAG,  position + " position "+ getTemplateKey(position) + " onBindViewHolder used " + (System.currentTimeMillis() - start)
-                  + " component " + component.hashCode());
-            }
-        }
-    }
-
-    @Override
-    public TemplateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        String template = mTemplateViewTypes.keyAt(viewType);
-        WXCell source = mTemplateSources.get(template);
-        if(source == null){
-            FrameLayout view = new FrameLayout(getContext());
-            view.setLayoutParams(new FrameLayout.LayoutParams(0, 0));
-            return new TemplateViewHolder(this, view, viewType);
-        }
-        WXCell component =  getCellTemplateFromCache(template);
-        boolean cacheHit = true;
-        if(component == null){
-            cacheHit = false;
-            if(!source.isSourceUsed()){
-                source.setSourceUsed(true);
-                renderTemplateCellWithData(source);
-                component = source;
-                if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
-                    WXLogUtils.d(TAG, template + " onCreateViewHolder source");
-                }
-            }
-        }
-        if(component == null) {
-            long start = System.currentTimeMillis();
-            component = (WXCell) copyComponentFromSourceCell(source);
-            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
-                WXLogUtils.d(TAG, template + " onCreateViewHolder copy used " + (System.currentTimeMillis() - start));
-            }
-        }
-        if(component.isLazy() || component.getHostView() == null) {
-            doCreateCellViewBindData(component, template, false);
-            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
-                WXLogUtils.d(TAG, template + " onCreateViewHolder  cache hit " + cacheHit   + " view not idle init");
-            }
-        }else{
-            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
-                WXLogUtils.d(TAG, template + " onCreateViewHolder  cache hit " + cacheHit + " view idle init " + component.hashCode()
-                 + "  " + source.hashCode());
-            }
-        }
-        TemplateViewHolder templateViewHolder = new TemplateViewHolder(this, component, viewType);
-        return  templateViewHolder;
-    }
-
-
-
-    /**
-     * @param position
-     * when template not send, return an invalid id, use empty view holder.
-     * when template has sended, use real template id to refresh view, use real view holder.
-     * */
-    @Override
-    public int getItemViewType(int position) {
-        String template = getTemplateKey(position);
-        int type =  mTemplateViewTypes.indexOfKey(template);
-        if(type < 0){
-            type = mTemplateViewTypes.indexOfKey(EMPTY_HOLDER_TEMPLATE_KEY);
-        }
-        return type;
-    }
-
-
-    /**
-     * create code context for render component and do render
-     * */
-    private List<WXComponent> doRenderTemplate(WXCell cell, int position){
-        this.cellRenderContext.clear();
-        Object item = cellDataManager.listData.get(position);
-        CellRenderState cellRenderState = cellDataManager.getRenderState(position);
-        cellRenderContext.renderState = cellRenderState;
-        cellRenderContext.templateList = this;
-        cellRenderContext.position = position;
-
-        ArrayStack stack = cellRenderContext.stack;
-        Map map = cellRenderContext.map;
-        if(cellDataManager.listData != null){
-            stack.push(map);
-            map.put(listDataKey, cellDataManager.listData);
-            if(!TextUtils.isEmpty(listDataIndexKey)) {
-                map.put(listDataIndexKey, new PositionRef(cellRenderState));
-            }
-            if(!TextUtils.isEmpty(listDataItemKey)) {
-                map.put(listDataItemKey, item);
-            }else{
-                stack.push(item);
-            }
-        }
-        if(cellRenderState.itemId <= 0){
-            getItemId(position);
-        }
-        List<WXComponent> updates = Statements.doRender(cell, this.cellRenderContext);
-        if(cellRenderState.isDirty()){
-            cellRenderState.resetDirty();
-        }
-        return  updates;
-    }
-
-    public ArrayStack copyStack(CellRenderContext context, ArrayStack stack){
-        ArrayStack onceStack = new ArrayStack();
-        for(int index=0;  index <  stack.size(); index++) {
-            Object value = stack.get(index);
-            if(value instanceof  Map){
-                value  = new HashMap((Map) value);
-            }
-            onceStack.push(value);
-        }
-        return onceStack;
-    }
-
-
-    /**
-     * return tepmlate key for position
-     * */
-    public String getTemplateKey(int position){
-        Object data =  safeGetListData(position);
-        return getTemplateKey(data);
-    }
-
-    /**
-     * return template key for position never be null
-     * */
-    public String getTemplateKey(Object data){
-        String template = null;
-        if(data instanceof  JSONObject) {
-            template = ((JSONObject)data).getString(listDataTemplateKey);
-        }
-        if(TextUtils.isEmpty(template)){
-            if(defaultTemplateCell != null){
-                template  = defaultTemplateKey;
-            }else {
-                template = "";
-            }
-        }
-        return  template;
-    }
-
-    /**
-     * get source template
-     * */
-    public WXCell getSourceTemplate(int position){
-        String template = getTemplateKey(position);
-        return mTemplateSources.get(template);
-    }
-
-
-
-    /**
-     * get template key from cell; -1 for  cann't find  type
-     * */
-    private int getCellTemplateItemType(WXCell cell){
-        if(cell == null){
-            return  -1;
-        }
-        if(cell.getAttrs() != null){
-            Object templateId = cell.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
-            String template = WXUtils.getString(templateId, null);
-            if(cell == defaultTemplateCell){
-                template = defaultTemplateKey;
-            }
-            int type =  mTemplateViewTypes.indexOfKey(template);
-            if(type < 0){
-                return -1;
-            }
-            return  type;
-        }
-        return  0;
-    }
-
-    @Override
-    public int getItemCount() {
-        if(!hasLayoutDone){
-            return 0;
-        }
-        if(!hasAppendTreeDone){
-            return 0;
-        }
-        if(cellDataManager.listData == null){
-            return  0;
-        }
-        if(mTemplateViewTypes == null || mTemplateViewTypes.size() <= 1){
-            return 0;
-        }
-        if(mTemplateSources == null || mTemplateSources.size() == 0){
-            return  0;
-        }
-        return cellDataManager.listData.size();
-    }
-
-    @Override
-    public boolean onFailedToRecycleView(TemplateViewHolder holder) {
-        return false;
-    }
-
-
-    /**
-     * @param position
-     * when template not send by javascript, return an invalid id, force  use empty view holder.
-     * when template has sended by javascript, use real template id to refresh view, use real view holder.
-     * */
-    @Override
-    public long getItemId(int position) {
-        CellRenderState renderState = cellDataManager.getRenderState(position);
-        if(renderState.itemId <=  0){
-            String template = getTemplateKey(position);
-            if(TextUtils.isEmpty(template)){
-                return RecyclerView.NO_ID;
-            }
-            Object data = safeGetListData(position);
-            if(data instanceof  JSONObject && ((JSONObject)data).containsKey("keyItemId")){
-                renderState.itemId =  ((JSONObject)data).getLongValue("keyItemId");
-            }else{
-                long id = Math.abs(data.hashCode());
-                long itemId = (id<< 24) + position;
-                renderState.itemId = itemId;
-            }
-        }
-        return renderState.itemId;
-    }
-
-    @Override
-    public void onBeforeScroll(int dx, int dy) {
-        if(mStickyHelper != null){
-            mStickyHelper.onBeforeScroll(dx, dy);
-        }
-    }
-
-    @Override
-    public void onLoadMore(int offScreenY) {
-        try {
-            String offset = getAttrs().getLoadMoreOffset();
-
-            if (TextUtils.isEmpty(offset)) {
-                offset = "0";
-            }
-            float offsetParsed = WXViewUtils.getRealPxByWidth(Integer.parseInt(offset),getInstance().getInstanceViewPortWidth());
-
-            if (offScreenY <= offsetParsed && cellDataManager.listData != null) {
-                if (mListCellCount != cellDataManager.listData.size()
-                        || mForceLoadmoreNextTime) {
-                    fireEvent(Constants.Event.LOADMORE);
-                    mListCellCount = cellDataManager.listData.size();
-                    mForceLoadmoreNextTime = false;
-                }
-            }
-        } catch (Exception e) {
-            if (WXEnvironment.isApkDebugable()){
-                WXLogUtils.d(TAG + " onLoadMore : ", e);
-            }
-        }
-    }
-
-    /**
-     *
-     * first fire appear event.
-     * */
-    @Override
-    public void notifyAppearStateChange(int firstVisible, int lastVisible, int directionX, int directionY) {
-        if(mAppearHelpers == null
-                || mAppearHelpers.size() <= 0){
-            return;
-        }
-        if(mAppearChangeRunnable != null) {
-            getHostView().removeCallbacks(mAppearChangeRunnable);
-            mAppearChangeRunnable = null;
-        }
-        String direction = directionY > 0 ? Constants.Value.DIRECTION_UP :
-                directionY < 0 ? Constants.Value.DIRECTION_DOWN : null;
-        if (getOrientation() == Constants.Orientation.HORIZONTAL && directionX != 0) {
-            direction = directionX > 0 ? Constants.Value.DIRECTION_LEFT : Constants.Value.DIRECTION_RIGHT;
-        }
-        RecyclerView recyclerView = getHostView().getInnerView();
-        for(int position=firstVisible; position<=lastVisible; position++){
-            int type = getItemViewType(position);
-            List<AppearanceHelper> helpers = mAppearHelpers.get(type);
-            if(helpers == null){
-                continue;
-            }
-            for(AppearanceHelper helper : helpers){
-                if(!helper.isWatch()){
-                    continue;
-                }
-                TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(position);
-                if(itemHolder == null || itemHolder.getComponent() == null){
-                    break;
-                }
-                List<WXComponent> childListeners = findChildListByRef(itemHolder.getComponent(), helper.getAwareChild().getRef());
-                if(childListeners == null || childListeners.size() == 0){
-                    break;
-                }
-
-                Map<String, Map<Integer, List<Object>>> disAppearList = mDisAppearWatchList.get(position);
-                if(disAppearList == null){
-                    disAppearList = new ArrayMap<>();
-                    mDisAppearWatchList.put(position, disAppearList);
-                }
-
-                Map<Integer, List<Object>> componentDisAppearList = disAppearList.get(helper.getAwareChild().getRef());
-                if(componentDisAppearList == null){
-                    componentDisAppearList = new ArrayMap<>();
-                    disAppearList.put(helper.getAwareChild().getRef(), componentDisAppearList);
-                }
-
-                for(int m=0; m<childListeners.size(); m++){
-                    WXComponent childLisener = childListeners.get(m);
-                    if(childLisener.getHostView() == null){
-                        continue;
-                    }
-                    boolean appear = helper.isViewVisible(childLisener.getHostView());
-                    int key = childLisener.getHostView().hashCode();
-                    if(appear){
-                        if(!componentDisAppearList.containsKey(key)){
-                            childLisener.notifyAppearStateChange(Constants.Event.APPEAR, direction);
-                            List<Object> eventArgs = null;
-                            if(childLisener.getEvents() != null
-                                    && childLisener.getEvents().getEventBindingArgsValues() != null
-                                    && childLisener.getEvents().getEventBindingArgsValues().get(Constants.Event.DISAPPEAR) != null){
-                                eventArgs = childLisener.getEvents().getEventBindingArgsValues().get(Constants.Event.DISAPPEAR);
-                            }
-                            componentDisAppearList.put(key, eventArgs);
-                        }
-                    }else{
-                        if(componentDisAppearList.containsKey(key)){
-                            childLisener.notifyAppearStateChange(Constants.Event.DISAPPEAR, direction);
-                            componentDisAppearList.remove(key);
-                        }
-                    }
-                }
-            }
-        }
-
-        //handle disappear event, out of position
-        int count = getItemCount();
-        for (int position=0; position<count; position++){
-            if(position >= firstVisible && position <= lastVisible){
-                position = lastVisible + 1;
-                continue;
-            }
-            Map<String, Map<Integer, List<Object>>> map = mDisAppearWatchList.get(position);
-            if(map == null){
-                continue;
-            }
-            WXCell template = mTemplateSources.get(getTemplateKey(position));
-            if(template == null){
-                return;
-            }
-            Set<Map.Entry<String, Map<Integer, List<Object>>>> cellWatcherEntries = map.entrySet();
-            for(Map.Entry<String,Map<Integer, List<Object>>> cellWatcherEntry : cellWatcherEntries){
-                String ref = cellWatcherEntry.getKey();
-                WXComponent component = findChildByRef(template, ref);
-                if(component == null){
-                    continue;
-                }
-                Map<Integer, List<Object>> eventWatchers = cellWatcherEntry.getValue();
-                if(eventWatchers == null || eventWatchers.size() == 0){
-                    continue;
-                }
-                WXEvent events = component.getEvents();
-                Set<Map.Entry<Integer, List<Object>>> eventWatcherEntries = eventWatchers.entrySet();
-                for(Map.Entry<Integer, List<Object>> eventWatcherEntry : eventWatcherEntries){
-                    events.putEventBindingArgsValue(Constants.Event.DISAPPEAR, eventWatcherEntry.getValue());
-                    component.notifyAppearStateChange(Constants.Event.DISAPPEAR, direction);
-                }
-                eventWatchers.clear();
-            }
-            mDisAppearWatchList.remove(position);
-        }
-    }
-
-
-    private Object safeGetListData(int position){
-        try{
-            return cellDataManager.listData.get(position);
-        }catch (Exception e){return  JSONObject.parseObject("{}");}
-    }
-
-    public void  notifyUpdateList(){
-        if(getHostView() == null
-                || getHostView().getInnerView() == null
-                || listUpdateRunnable == null){
-            return;
-        }
-        if(Looper.getMainLooper().getThread().getId() != Thread.currentThread().getId()){
-            getHostView().removeCallbacks(listUpdateRunnable);
-            getHostView().post(listUpdateRunnable);
-        }else{
-            listUpdateRunnable.run();
-        }
-    }
-
-    private int calcContentSize() {
-        int totalHeight = 0;
-        if(cellDataManager.listData == null){
-            return totalHeight;
-        }
-        for (int i = 0; i < cellDataManager.listData.size(); i++) {
-            WXCell child = getSourceTemplate(i);
-            if (child != null) {
-                totalHeight += child.getLayoutHeight();
-            }
-        }
-        return totalHeight;
-    }
-
-    public int calcContentOffset(RecyclerView recyclerView) {
-        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-        if (layoutManager instanceof LinearLayoutManager) {
-            int firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
-            int offset = 0;
-            for (int i=0;i<firstVisibleItemPosition;i++) {
-                WXCell cell = getSourceTemplate(i);
-                if(cell == null){
-                    continue;
-                }
-                offset -= cell.getLayoutHeight();
-            }
-
-            if (layoutManager instanceof GridLayoutManager) {
-                int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
-                offset = offset / spanCount;
-            }
-            View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
-            if(firstVisibleView != null) {
-                offset += firstVisibleView.getTop();
-            }
-            return offset;
-        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
-            int spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
-            int firstVisibleItemPosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(null)[0];
-            int offset = 0;
-            for (int i=0;i<firstVisibleItemPosition;i++) {
-                WXCell cell = getSourceTemplate(i);
-                if(cell == null){
-                    continue;
-                }
-                offset -= cell.getLayoutHeight();
-            }
-            offset = offset / spanCount;
-
-            View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
-            if(firstVisibleView != null) {
-                offset += firstVisibleView.getTop();
-            }
-            return offset;
-        }
-        return -1;
-    }
-
-    /**
-     * find certain class type parent
-     * */
-    public WXComponent findParentType(WXComponent component, Class type){
-        if(type.isAssignableFrom(component.getClass())){
-            return component;
-        }
-        if(component.getParent() != null) {
-            findTypeParent(component.getParent(), type);
-        }
-        return  null;
-    }
-
-
-    /**
-     * find child by ref
-     * */
-    public WXComponent findChildByRef(WXComponent component, String ref){
-        if(ref.equals(component.getRef())){
-            return component;
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            for(int i=0; i<container.getChildCount(); i++){
-                WXComponent child = findChildByRef(container.getChild(i), ref);
-                if(child != null){
-                    return  child;
-                }
-            }
-        }
-        return  null;
-    }
-
-    /**
-     * find child list, has same ref
-     * */
-    public List<WXComponent> findChildListByRef(WXComponent component, String ref){
-        WXComponent child = findChildByRef(component, ref);
-        if(child == null){
-            return  null;
-        }
-        List<WXComponent> componentList = new ArrayList<>();
-        WXVContainer container = child.getParent();
-        if(container != null && (!(container instanceof WXRecyclerTemplateList))){
-            for(int i=0; i<container.getChildCount(); i++){
-                WXComponent element = container.getChild(i);
-                if(ref.equals(element.getRef())){
-                    componentList.add(element);
-                }
-            }
-        }else{
-            componentList.add(child);
-        }
-        return  componentList;
-    }
-
-
-
-    /**
-     * find child by ref
-     * */
-    public WXComponent findChildByAttrsRef(WXComponent component, String ref){
-        if(component.getAttrs() != null && ref.equals(component.getAttrs().get(TemplateDom.ATTRS_KEY_REF))){
-            return component;
-        }
-        if(component instanceof WXVContainer){
-            WXVContainer container = (WXVContainer) component;
-            for(int i=0; i<container.getChildCount(); i++){
-                WXComponent child = findChildByAttrsRef(container.getChild(i), ref);
-                if(child != null){
-                    return  child;
-                }
-            }
-        }
-        return  null;
-    }
-
-
-
-    /**
-     * @param  template  template name
-     * get cell template component from cache, if cell component not load
-     * start load cell template
-     * */
-    private WXCell getCellTemplateFromCache(final String template){
-        TemplateCache cache = mTemplatesCache.get(template);
-        WXCell component =  null;
-        if(cache != null && cache.cells != null && cache.cells.size() > 0){
-            component = cache.cells.poll();
-        }
-        if(cache == null ||  !cache.isLoadIng){
-            if(cache == null){
-                cache = new TemplateCache();
-                mTemplatesCache.put(template, cache);
-            }
-            cache.isLoadIng = true;
-            WXCell source = mTemplateSources.get(template);
-            if(source != null){
-                boolean allowPreload = WXUtils.getBoolean(source.getAttrs().get("preload"), true);
-                if(allowPreload) {
-                    AsyncCellLoadTask asyncCellLoadTask = new AsyncCellLoadTask(template, source, this);
-                    asyncCellLoadTask.startTask();
-                }
-            }
-        }
-        return  component;
-    }
-
-    /**
-     * copy cell component from source, init render data, and return source
-     * if none data, return null
-     * */
-    public WXComponent copyComponentFromSourceCell(WXCell cell){
-        renderTemplateCellWithData(cell);
-        WXCell component = (WXCell) Statements.copyComponentTree(cell);
-        return component;
-    }
-
-    /**
-     *  render  init with  cell with one data,
-     *  if template has already render with data, done nothing
-     *  @param  cell
-     * */
-    private synchronized void renderTemplateCellWithData(WXCell cell){
-        if(cell.getRenderData() == null){
-            if(cellDataManager.listData != null && cellDataManager.listData.size() > 0){
-                synchronized (this){
-                    if(cell.getRenderData() == null){
-                        Statements.parseStatementsToken(cell);
-                        for(int i = 0; i< cellDataManager.listData.size(); i++){
-                            if(cell == getSourceTemplate(i)){
-                                Object data = cellDataManager.listData.get(i);
-                                doRenderTemplate(cell, i);
-                                Layouts.doLayoutSync(cell, getLayoutWidth(), getLayoutHeight());
-                                cell.setRenderData(data);
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-
-    /**
-     * create view for lazy cell and bind data
-     * */
-    public static void doCreateCellViewBindData(WXCell component, String template, boolean inPreload){
-        if(component.isLazy() || component.getHostView() == null){
-            long start = System.currentTimeMillis();
-            Statements.initLazyComponent(component, null);
-            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
-                WXLogUtils.d(TAG, " doCreateCellViewBindData " + template + " in preload "+ inPreload + " used " + (System.currentTimeMillis() - start));
-            }
-        }
-    }
-
-    public ScrollStartEndHelper getScrollStartEndHelper() {
-        if(mScrollStartEndHelper == null){
-            mScrollStartEndHelper = new ScrollStartEndHelper(this);
-        }
-        return mScrollStartEndHelper;
-    }
-
-    public int getTemplateCacheSize() {
-        return templateCacheSize;
-    }
-
-    public ConcurrentHashMap<String, TemplateCache> getTemplatesCache() {
-        if(mTemplatesCache == null){
-            mTemplatesCache = new ConcurrentHashMap<>();
-        }
-        return mTemplatesCache;
-    }
-
-
-    public CellDataManager getCellDataManager() {
-        return cellDataManager;
-    }
-
-
-    private JSONArray parseListDataToJSONArray(Object value){
-        try{
-            if(value instanceof  JSONArray){
-                return (JSONArray) value;
-            }
-            if(value instanceof String){
-                JSONArray array = JSONArray.parseArray(getAttrs().get(Constants.Name.Recycler.LIST_DATA).toString());
-                return array;
-            }
-        }catch (Exception e){
-            WXLogUtils.e(TAG, "parseListDataException" + e.getMessage());
-        }
-        return new JSONArray();
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java
deleted file mode 100644
index 443dcf6..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template.jni;
-
-public class NativeRenderLayoutDirection {
-    public static final int inherit = 0;
-    public static final int ltr = 1;
-    public static final int rtl = 2;
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
deleted file mode 100644
index 12f125a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list.template.jni;
-
-import android.util.Log;
-
-import com.taobao.weex.base.CalledByNative;
-import com.taobao.weex.ui.component.WXComponent;
-
-/**
- * Created by furture on 2018/5/3.
- */
-
-public class NativeRenderObjectUtils {
-
-
-    /**
-     * getRenderObject
-     * */
-    public static native long nativeGetRenderObject(String instanceId, String ref);
-
-    /**
-     * render object layout
-     * */
-    public static native void nativeUpdateRenderObjectStyle(long ptr, String key, String value);
-    public static native void nativeUpdateRenderObjectAttr(long ptr, String key, String value);
-
-    /**
-     * copy render object
-     * */
-    public static native long nativeCopyRenderObject(long ptr);
-
-    /**
-     * layout render object
-     * */
-    public static native int nativeLayoutRenderObject(long ptr, float width, float height);
-
-    public static native int nativeRenderObjectGetLayoutDirectionFromPathNode(long ptr);
-    /**
-     * get child length
-     * */
-    public static native void nativeAddChildRenderObject(long parent, long child);
-
-    /**
-     * get component, tranverse child and update component
-     * */
-    public static native boolean nativeRenderObjectHasNewLayout(long ptr);
-    public static native int nativeRenderObjectChildCount(long ptr);
-    public static native long nativeRenderObjectGetChild(long ptr, int index);
-    public static native void nativeRenderObjectUpdateComponent(long ptr, WXComponent component);
-    public static native void nativeRenderObjectChildWaste(long ptr, boolean waster);
-
-
-    /**
-     * component size
-     * */
-    @CalledByNative
-    public static void updateComponentSize(WXComponent component, float top, float bottom, float left, float right, float height, float width){
-        component.updateDemission(top, bottom, left, right, height, width);
-        component.applyLayoutOnly();
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/OnActivePseudoListner.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/OnActivePseudoListner.java
deleted file mode 100644
index 961e3b8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/OnActivePseudoListner.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.pesudo;
-
-/**
- * Created by sospartan on 05/01/2017.
- */
-public interface OnActivePseudoListner {
-  void updateActivePseudo(boolean isSet);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/PesudoStatus.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/PesudoStatus.java
deleted file mode 100644
index 04e5fee..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/PesudoStatus.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.pesudo;
-
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-
-import com.taobao.weex.common.Constants;
-
-import java.util.Map;
-
-/**
- * Created by sospartan on 05/01/2017.
- */
-
-public class PesudoStatus {
-
-  /**
-   * See {@link Constants.PSEUDO}
-   */
-  private int[] mStatuses = new int[4];
-
-  private static final int UNSET = 0;
-  private static final int SET = 1;
-
-  static final int CLASS_ACTIVE = 0;
-  static final int CLASS_FOCUS = 1;
-  static final int CLASS_ENABLED = 2;
-  static final int CLASS_DISABLED = 3;
-
-  public PesudoStatus(){
-    for (int i = 0; i < mStatuses.length; i++) {
-        mStatuses[i] = UNSET;
-    }
-  }
-
-  /**
-   *
-   * @param clzName See {@link Constants.PSEUDO}
-   * @param status
-   */
-  public void setStatus(String clzName,boolean status){
-    switch (clzName){
-      case Constants.PSEUDO.ACTIVE:
-        setStatus(PesudoStatus.CLASS_ACTIVE,status);
-        break;
-      case Constants.PSEUDO.DISABLED:
-        setStatus(PesudoStatus.CLASS_DISABLED,status);
-        break;
-      case Constants.PSEUDO.ENABLED:
-        setStatus(PesudoStatus.CLASS_ENABLED,status);
-        break;
-      case Constants.PSEUDO.FOCUS:
-        setStatus(PesudoStatus.CLASS_FOCUS,status);
-        break;
-    }
-  }
-
-  void setStatus(int clz,boolean status){
-    mStatuses[clz] = status?SET:UNSET;
-  }
-
-  public boolean isSet(int clz){
-    return mStatuses[clz] == SET;
-  }
-
-  public @Nullable String getStatuses(){
-    StringBuilder sb = new StringBuilder();
-    if(isSet(CLASS_ACTIVE)){
-      sb.append(Constants.PSEUDO.ACTIVE);
-    }
-    if(isSet(CLASS_DISABLED)){
-      sb.append(Constants.PSEUDO.DISABLED);
-    }
-    //enabled is ignored
-
-    if(isSet(CLASS_FOCUS) && !isSet(CLASS_DISABLED)){
-      sb.append(Constants.PSEUDO.FOCUS);
-    }
-    return sb.length()==0?null:sb.toString();
-  }
-
-  public Map<String,Object> updateStatusAndGetUpdateStyles(String clzName,
-                                                           boolean status,
-                                                           Map<String, Map<String,Object>> pesudoStyles,
-                                                           Map<String,Object> originalStyles){
-    String prevStatusesStr = getStatuses();//before change
-    setStatus(clzName,status);
-    String statusesStr = getStatuses();//after change
-
-    Map<String,Object> updateStyles = pesudoStyles.get(statusesStr);
-    Map<String,Object> prevUpdateStyles = pesudoStyles.get(prevStatusesStr);
-
-    /**
-     * NEW INSTANCE, DO NOT USE MAP OBJECT FROM pesudoStyles
-     */
-    Map<String,Object> resultStyles = new ArrayMap<>();
-    if(prevUpdateStyles != null){
-      resultStyles.putAll(prevUpdateStyles);
-    }
-
-    //reset
-    for (String key : resultStyles.keySet()) {
-      resultStyles.put(key, originalStyles.containsKey(key) ? originalStyles.get(key) : "");
-    }
-
-    //apply new update
-    if(updateStyles != null) {
-      for (Map.Entry<String, Object> entry : updateStyles.entrySet()) {
-        resultStyles.put(entry.getKey(), entry.getValue());
-      }
-    }
-    return resultStyles;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/TouchActivePseudoListener.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/TouchActivePseudoListener.java
deleted file mode 100644
index 1834675..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/pesudo/TouchActivePseudoListener.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.pesudo;
-
-import android.annotation.SuppressLint;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * Created by sospartan on 05/01/2017.
- */
-public class TouchActivePseudoListener implements View.OnTouchListener {
-  private OnActivePseudoListner mOnActivePseudoListner;
-  private boolean mIsConsumeOnTouch;
-
-  public TouchActivePseudoListener(OnActivePseudoListner l, boolean consumeInTouch) {
-    mOnActivePseudoListner = l;
-    mIsConsumeOnTouch = consumeInTouch;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouch(View v, MotionEvent event) {
-    int action = event.getAction();
-    if (mOnActivePseudoListner != null) {
-      if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
-        mOnActivePseudoListner.updateActivePseudo(true);
-      } else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
-        mOnActivePseudoListner.updateActivePseudo(false);
-      }
-    }
-    return mIsConsumeOnTouch;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/WXRichText.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/WXRichText.java
deleted file mode 100755
index 06357a6..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/WXRichText.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext;
-
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.SpannedString;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.layout.measurefunc.TextContentBoxMeasurement;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXText;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.component.richtext.node.RichTextNode;
-import com.taobao.weex.ui.component.richtext.node.RichTextNodeManager;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public class WXRichText extends WXText {
-  private List<RichTextNode> nodes = new LinkedList<>();
-
-  static class RichTextContentBoxMeasurement extends TextContentBoxMeasurement {
-
-    public RichTextContentBoxMeasurement(WXComponent component) {
-      super(component);
-    }
-
-    @NonNull
-    @Override
-    protected Spanned createSpanned(String text) {
-      if(!TextUtils.isEmpty(text)) {
-        if (mComponent.getInstance() != null & mComponent.getInstance().getUIContext() != null &&
-                !TextUtils.isEmpty(mComponent.getInstanceId())) {
-          Spannable spannable = RichTextNode.parse(
-                  mComponent.getInstance().getUIContext(),
-                  mComponent.getInstanceId(),
-                  mComponent.getRef(),
-                  text);
-          updateSpannable(spannable, RichTextNode.createSpanFlag(0));
-          return spannable;
-        } else {
-          return new SpannedString("");
-        }
-      }
-      else {
-        Spannable spannable = ((WXRichText)mComponent).toSpan();
-        updateSpannable(spannable, RichTextNode.createSpanFlag(0));
-        return spannable;
-        }
-    }
-  }
-
-  public static class Creator implements ComponentCreator {
-
-    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-      return new WXRichText(instance, parent, basicComponentData);
-    }
-  }
-
-  public WXRichText(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-    setContentBoxMeasurement(new RichTextContentBoxMeasurement(this));
-  }
-  public void AddChildNode(String ref, String nodeType,String parentRef, Map<String,String> styles,Map<String,String> attrs) {
-    if(getInstance() != null && getInstance().getUIContext() != null && !TextUtils.isEmpty(getInstanceId()) &&
-            !TextUtils.isEmpty(ref) && !TextUtils.isEmpty(nodeType)) {
-      RichTextNode child = RichTextNodeManager.createRichTextNode(getInstance().getUIContext(), getInstanceId(), getRef(), ref, nodeType, styles, attrs);
-      if (TextUtils.isEmpty(parentRef)) {
-        nodes.add(child);
-      } else {
-        RichTextNode parent = findRichNode(parentRef);
-        if (parent != null) {
-          parent.addChildNode(child);
-        }
-      }
-    }
-  }
-  private Spannable toSpan(){
-    SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
-    if(nodes != null && !nodes.isEmpty()){
-      for(RichTextNode node:nodes){
-        spannableStringBuilder.append(node.toSpan(1));
-      }
-    }
-    return spannableStringBuilder;
-  }
-
-  public void removeChildNode(String parentRef,String ref) {
-    if (nodes != null && !nodes.isEmpty()) {
-      if (parentRef.equals("")) {
-        for (RichTextNode node : nodes) {
-          if (TextUtils.equals(node.getRef(), ref)) {
-            nodes.remove(node);
-          }
-        }
-      } else {
-        RichTextNode parent = findRichNode(parentRef);
-        if (parent != null) {
-          parent.removeChildNode(ref);
-        }
-      }
-    }
-  }
-  public void updateChildNodeStyles(String ref,Map<String,Object> styles){
-    RichTextNode node = findRichNode(ref);
-    if(node != null){
-      node.updateStyles(styles);
-    }
-  }
-  public void updateChildNodeAttrs(String ref,Map<String,Object> attrs){
-    RichTextNode node = findRichNode(ref);
-    if(node != null){
-      node.updateAttrs(attrs);
-    }
-  }
-  private RichTextNode findRichNode(String ref){
-    if(!TextUtils.isEmpty(ref)) {
-      RichTextNode theNode;
-      if (nodes != null && !nodes.isEmpty()) {
-        for (RichTextNode node : nodes) {
-          if ((theNode = node.findRichNode(ref)) != null)
-            return theNode;
-        }
-      }
-    }
-    return null;
-  }
-
-  @Override
-  protected WXRichTextView initComponentHostView(@NonNull Context context) {
-    return new WXRichTextView(context);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/WXRichTextView.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/WXRichTextView.java
deleted file mode 100644
index 4605201..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/WXRichTextView.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.text.Layout;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.Spanned;
-import android.text.style.ClickableSpan;
-import android.view.MotionEvent;
-import android.widget.TextView;
-
-import com.taobao.weex.ui.component.richtext.span.ImgSpan;
-import com.taobao.weex.ui.view.WXTextView;
-
-public class WXRichTextView extends WXTextView {
-
-  public WXRichTextView(Context context) {
-    super(context);
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    boolean superResult = super.onTouchEvent(event);
-    boolean handled = false;
-    if (isEnabled() && getTextLayout() != null && getText() instanceof Spannable) {
-      Spannable spannable = (Spannable) getText();
-      handled = updateSelection(event, spannable);
-    }
-    return handled || superResult;
-  }
-
-  @Override
-  protected boolean verifyDrawable(Drawable who) {
-    super.verifyDrawable(who);
-    return true;
-  }
-
-  @Override
-  public void setTextLayout(Layout layout) {
-    super.setTextLayout(layout);
-    if (layout.getText() instanceof Spanned) {
-      Spanned spanned = (Spanned) layout.getText();
-      ImgSpan[] imgSpan = spanned.getSpans(0, spanned.length(), ImgSpan.class);
-      if (imgSpan != null) {
-        for (ImgSpan span : imgSpan) {
-          span.setView(this);
-        }
-      }
-    }
-  }
-
-  /**
-   * Mostly copied from
-   * {@link android.text.method.LinkMovementMethod#onTouchEvent(TextView, Spannable, MotionEvent)}.
-   */
-  private boolean updateSelection(MotionEvent event, Spannable buffer) {
-    int action = event.getActionMasked();
-
-    if (action == MotionEvent.ACTION_UP ||
-        action == MotionEvent.ACTION_DOWN) {
-      int x = (int) event.getX();
-      int y = (int) event.getY();
-
-      x -= getPaddingLeft();
-      y -= getPaddingTop();
-
-      x += getScrollX();
-      y += getScrollY();
-
-      Layout layout = getTextLayout();
-      int line = layout.getLineForVertical(y);
-      int off = layout.getOffsetForHorizontal(line, x);
-
-      ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
-
-      if (link.length != 0) {
-        if (action == MotionEvent.ACTION_UP) {
-          link[0].onClick(this);
-        } else {
-          Selection.setSelection(buffer,
-                                 buffer.getSpanStart(link[0]),
-                                 buffer.getSpanEnd(link[0]));
-        }
-
-        return true;
-      } else {
-        Selection.removeSelection(buffer);
-      }
-    }
-
-    return false;
-  }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/ANode.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/ANode.java
deleted file mode 100755
index b657188..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/ANode.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.node;
-
-import android.content.Context;
-import android.support.v4.util.ArrayMap;
-import android.text.SpannableStringBuilder;
-
-import com.taobao.weex.ui.component.richtext.span.ASpan;
-import com.taobao.weex.ui.component.richtext.span.ItemClickSpan;
-
-import java.util.ArrayList;
-import java.util.Map;
-
-class ANode extends RichTextNode {
-
-  static class ANodeCreator implements RichTextNodeCreator<ANode> {
-
-    @Override
-    public ANode createRichTextNode(Context context, String instanceId, String componentRef) {
-      return new ANode(context, instanceId, componentRef);
-    }
-    @Override
-    public ANode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
-                                      Map<String,Object> styles, Map<String,Object> attrs){
-      return new ANode(context,instanceId,componentRef,ref,styles,attrs);
-    }
-
-  }
-
-  public static final String NODE_TYPE = "a";
-  public static final String HREF = "href";
-
-  private ANode(Context context, String instanceId, String componentRef) {
-    super(context, instanceId, componentRef);
-  }
-  private ANode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles, Map<String,Object> attrs) {
-    super(context, instanceId, componentRef, ref, styles, attrs);
-  }
-
-  @Override
-  public String toString() {
-    return "";
-  }
-
-  @Override
-  protected boolean isInternalNode() {
-    return true;
-  }
-
-  @Override
-  protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
-    super.updateSpans(spannableStringBuilder, level);
-      if (attr != null && attr.containsKey(RichTextNode.PSEUDO_REF)) {
-          ItemClickSpan itemClickSpan = new ItemClickSpan(mInstanceId, mComponentRef, attr.get(RichTextNode.PSEUDO_REF).toString());
-          spannableStringBuilder.setSpan(itemClickSpan, 0, spannableStringBuilder.length(),
-                  createSpanFlag(level));
-      } else if (attr != null && attr.containsKey(HREF)) {
-          ASpan aSpan = new ASpan(mInstanceId, attr.get(HREF).toString());
-          spannableStringBuilder.setSpan(aSpan, 0, spannableStringBuilder.length(),
-                  createSpanFlag(level));
-      }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/ImgNode.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/ImgNode.java
deleted file mode 100755
index 69f66ee..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/ImgNode.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.node;
-
-import static com.taobao.weex.utils.WXViewUtils.getRealPxByWidth;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.v4.util.ArrayMap;
-import android.text.SpannableStringBuilder;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.DrawableStrategy;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.component.richtext.span.ImgSpan;
-import com.taobao.weex.ui.component.richtext.span.ItemClickSpan;
-import com.taobao.weex.utils.ImgURIUtil;
-import com.taobao.weex.utils.WXUtils;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-class ImgNode extends RichTextNode {
-
-  static class ImgNodeCreator implements RichTextNodeCreator<ImgNode> {
-
-    @Override
-    public ImgNode createRichTextNode(Context context, String instanceId, String componentRef) {
-      return new ImgNode(context, instanceId, componentRef);
-    }
-    @Override
-    public ImgNode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
-                                       Map<String,Object> styles, Map<String,Object> attrs){
-      return new ImgNode(context,instanceId,componentRef,ref,styles,attrs);
-    }
-  }
-
-  public static final String NODE_TYPE = "image";
-
-  private ImgNode(Context context, String instanceId, String componentRef) {
-    super(context, instanceId, componentRef);
-  }
-  private ImgNode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles, Map<String,Object> attrs) {
-    super(context, instanceId, componentRef, ref, styles, attrs);
-  }
-
-  @Override
-  public String toString() {
-    return "\uFEFF";
-  }
-
-  @Override
-  protected boolean isInternalNode() {
-    return false;
-  }
-
-  @Override
-  protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
-    if (WXSDKEngine.getDrawableLoader() != null &&
-        style.containsKey(Constants.Name.WIDTH) &&
-        style.containsKey(Constants.Name.HEIGHT) &&
-        attr.containsKey(Constants.Name.SRC) &&
-        instance != null) {
-      List<Object> spans = new LinkedList<>();
-      spans.add(createImgSpan(instance));
-
-      if (attr.containsKey(RichTextNode.PSEUDO_REF)) {
-        spans.add(new ItemClickSpan(mInstanceId, mComponentRef,
-            attr.get(RichTextNode.PSEUDO_REF).toString()));
-      }
-
-      for (Object span : spans) {
-        spannableStringBuilder.setSpan(
-            span, 0, spannableStringBuilder.length(), createSpanFlag(level));
-      }
-    }
-  }
-
-  @NonNull
-  private ImgSpan createImgSpan(WXSDKInstance instance) {
-    int width = (int) getRealPxByWidth(WXUtils.getFloat(style.get(Constants.Name.WIDTH)),
-        instance.getInstanceViewPortWidth());
-    int height = (int) getRealPxByWidth(WXUtils.getFloat(style.get(Constants.Name.HEIGHT)),
-        instance.getInstanceViewPortWidth());
-    ImgSpan imageSpan = new ImgSpan(width, height);
-
-    String url = attr.get(Constants.Name.SRC).toString();
-    Uri rewrited = instance.rewriteUri(Uri.parse(url), URIAdapter.IMAGE);
-    if (Constants.Scheme.LOCAL.equals(rewrited.getScheme())) {
-      Drawable localDrawable = ImgURIUtil.getDrawableFromLoaclSrc(mContext, rewrited);
-      imageSpan.setDrawable(localDrawable, false);
-    } else {
-      DrawableStrategy drawableStrategy = new DrawableStrategy();
-      drawableStrategy.width = width;
-      drawableStrategy.height = height;
-      WXSDKEngine.getDrawableLoader().setDrawable(rewrited.toString(), imageSpan, drawableStrategy);
-    }
-    return imageSpan;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNode.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNode.java
deleted file mode 100755
index 036940b..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNode.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.node;
-
-import static com.taobao.weex.dom.WXStyle.UNSET;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextUtils;
-import android.text.style.AbsoluteSizeSpan;
-import android.text.style.BackgroundColorSpan;
-import android.text.style.ForegroundColorSpan;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.WXCustomStyleSpan;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXResourceUtils;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public abstract class RichTextNode {
-
-    public static final String TYPE = "type";
-    public static final String STYLE = "style";
-    public static final String ATTR = "attr";
-    public static final String CHILDREN = "children";
-    public static final String VALUE = Constants.Name.VALUE;
-    public static final String ITEM_CLICK="itemclick";
-    public static final String PSEUDO_REF="pseudoRef";
-    private static final int MAX_LEVEL = Spanned.SPAN_PRIORITY >> Spanned.SPAN_PRIORITY_SHIFT;
-
-    protected final Context mContext;
-    protected final String mInstanceId;
-    protected final String mComponentRef;
-    protected final String mRef;
-    protected Map<String, Object> style;
-    protected Map<String, Object> attr;
-    protected List<RichTextNode> children;
-
-    protected RichTextNode(Context context, String instanceId, String componentRef) {
-        mContext = context;
-        mInstanceId = instanceId;
-        mComponentRef = componentRef;
-        mRef = null;
-    }
-    protected RichTextNode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles, Map<String,Object> attrs) {
-        mContext = context;
-        mInstanceId = instanceId;
-        mComponentRef = componentRef;
-        mRef = ref;
-        if(styles != null){
-            style = styles;
-        }
-        else {
-            style = new ArrayMap<>(0);
-        }
-        if (attrs != null) {
-            attr = attrs;
-        } else {
-            attr = new ArrayMap<>(0);
-        }
-        children = new LinkedList<>();
-    }
-
-    public static
-    @NonNull
-    Spannable parse(@NonNull Context context, @NonNull String instanceId, @NonNull String componentRef, String json) {
-        JSONArray jsonArray = JSON.parseArray(json);
-        JSONObject jsonObject;
-        List<RichTextNode> nodes;
-        RichTextNode node;
-        if (jsonArray != null && !jsonArray.isEmpty()) {
-            nodes = new ArrayList<>(jsonArray.size());
-            for (int i = 0; i < jsonArray.size(); i++) {
-                jsonObject = jsonArray.getJSONObject(i);
-                if (jsonObject != null) {
-                    node = RichTextNodeManager.createRichTextNode(context, instanceId, componentRef, jsonObject);
-                    if (node != null) {
-                        nodes.add(node);
-                    }
-                }
-            }
-            return parse(nodes);
-        }
-        return new SpannableString("");
-    }
-
-    public static int createSpanFlag(int level) {
-        return createPriorityFlag(level) | Spanned.SPAN_INCLUSIVE_EXCLUSIVE;
-    }
-
-    @Override
-    public abstract String toString();
-
-    protected abstract boolean isInternalNode();
-
-    public String getRef(){
-        return mRef;
-    }
-
-    final void parse(@NonNull Context context, @NonNull String instanceId, @NonNull String componentRef, JSONObject jsonObject) {
-        JSONObject jsonStyle, jsonAttr, child;
-        JSONArray jsonChildren;
-        RichTextNode node;
-        if ((jsonStyle = jsonObject.getJSONObject(STYLE)) != null) {
-            style = new ArrayMap<>();
-            style.putAll(jsonStyle);
-        } else {
-            style = new ArrayMap<>(0);
-        }
-
-        if ((jsonAttr = jsonObject.getJSONObject(ATTR)) != null) {
-            attr = new ArrayMap<>(jsonAttr.size());
-            attr.putAll(jsonAttr);
-        } else {
-            attr = new ArrayMap<>(0);
-        }
-
-        if ((jsonChildren=jsonObject.getJSONArray(CHILDREN))!=null) {
-            children = new ArrayList<>(jsonChildren.size());
-            for (int i = 0; i < jsonChildren.size(); i++) {
-                child = jsonChildren.getJSONObject(i);
-                node = RichTextNodeManager.createRichTextNode(context, instanceId, componentRef, child);
-                if (node != null) {
-                    children.add(node);
-                }
-            }
-        } else {
-            children = new ArrayList<>(0);
-        }
-    }
-    public void addChildNode(RichTextNode child){
-        if(children == null){
-            children = new LinkedList<>();
-        }
-        if(child != null && isInternalNode()){
-            children.add(child);
-        }
-    }
-    public void removeChildNode(String ref){
-        if(children != null && !children.isEmpty() && !TextUtils.isEmpty(ref)){
-            try {
-                for (RichTextNode child : children) {
-                    if (TextUtils.equals(child.mRef, ref)) {
-                        children.remove(child);
-                    }
-                }
-            }catch(Exception e){
-                WXLogUtils.getStackTrace(e);
-            }
-        }
-    }
-    public void updateStyles(Map<String,Object> styles){
-        if(styles != null && !styles.isEmpty()){
-            style.putAll(styles);
-        }
-    }
-    public void updateAttrs(Map<String,Object> attrs){
-        if(attr != null && !attrs.isEmpty()){
-            attr.putAll(attrs);
-        }
-    }
-
-    protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
-        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
-        if (style != null && instance != null) {
-            List<Object> spans = new LinkedList<>();
-
-            WXCustomStyleSpan customStyleSpan = createCustomStyleSpan();
-            if (customStyleSpan != null) {
-                spans.add(customStyleSpan);
-            }
-
-            if (style.containsKey(Constants.Name.FONT_SIZE)) {
-                spans.add(new AbsoluteSizeSpan(WXStyle.getFontSize(style, instance.getInstanceViewPortWidth())));
-            }
-
-            if (style.containsKey(Constants.Name.BACKGROUND_COLOR)) {
-                int color = WXResourceUtils.getColor(style.get(Constants.Name.BACKGROUND_COLOR).toString(),
-                    Color.TRANSPARENT);
-                if (color != Color.TRANSPARENT) {
-                    spans.add(new BackgroundColorSpan(color));
-                }
-            }
-
-            if (style.containsKey(Constants.Name.COLOR)) {
-                spans.add(new ForegroundColorSpan(WXResourceUtils.getColor(WXStyle.getTextColor(style))));
-            }
-
-            int spanFlag = createSpanFlag(level);
-            for (Object span : spans) {
-                spannableStringBuilder.setSpan(span, 0, spannableStringBuilder.length(), spanFlag);
-            }
-        }
-    }
-
-    private static int createPriorityFlag(int level) {
-        return level <= MAX_LEVEL ?
-            (MAX_LEVEL - level) << Spanned.SPAN_PRIORITY_SHIFT :
-            MAX_LEVEL << Spanned.SPAN_PRIORITY_SHIFT;
-    }
-
-
-    private static
-    @NonNull
-    Spannable parse(@NonNull List<RichTextNode> list) {
-        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
-        for (RichTextNode richTextNode : list) {
-            spannableStringBuilder.append(richTextNode.toSpan(1));
-        }
-        return spannableStringBuilder;
-    }
-
-    public Spannable toSpan(int level) {
-        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
-        spannableStringBuilder.append(toString());
-        if (isInternalNode() && children != null) {
-            for (RichTextNode child : children) {
-                spannableStringBuilder.append(child.toSpan(level + 1));
-            }
-        }
-        updateSpans(spannableStringBuilder, level);
-        return spannableStringBuilder;
-    }
-
-    private
-    @Nullable
-    WXCustomStyleSpan createCustomStyleSpan() {
-        int fontWeight = UNSET, fontStyle = UNSET;
-        String fontFamily = null;
-        if (style.containsKey(Constants.Name.FONT_WEIGHT)) {
-            fontWeight = WXStyle.getFontWeight(style);
-        }
-        if (style.containsKey(Constants.Name.FONT_STYLE)) {
-            fontStyle = WXStyle.getFontStyle(style);
-        }
-        if (style.containsKey(Constants.Name.FONT_FAMILY)) {
-            fontFamily = WXStyle.getFontFamily(style);
-        }
-        if (fontWeight != UNSET
-            || fontStyle != UNSET
-            || fontFamily != null) {
-            return new WXCustomStyleSpan(fontStyle, fontWeight, fontFamily);
-        } else {
-            return null;
-        }
-    }
-    public RichTextNode findRichNode(String ref){
-        RichTextNode theNode;
-        if(mRef != null && TextUtils.equals(mRef,ref)){
-            return this;
-        }
-        if(children != null && !children.isEmpty()){
-            for (RichTextNode child:children) {
-                if((theNode = child.findRichNode(ref)) != null)
-                    return theNode;
-            }
-        }
-        return null;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNodeCreator.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNodeCreator.java
deleted file mode 100755
index faaf6ca..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNodeCreator.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.node;
-
-import android.content.Context;
-
-import java.util.Map;
-
-public interface RichTextNodeCreator<T extends RichTextNode> {
-
-  T createRichTextNode(Context context, String instanceId, String componentRef);
-  T createRichTextNode(Context context,String instanceId,String componentRef,String ref,Map<String,Object> styles, Map<String,Object> attrs);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNodeManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNodeManager.java
deleted file mode 100755
index d47cabc..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/RichTextNodeManager.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.node;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.Map;
-
-public class RichTextNodeManager {
-
-  private final static Map<String, RichTextNodeCreator>
-      registeredTextNodes = new ArrayMap<>();
-
-  static {
-    registeredTextNodes.put(SpanNode.NODE_TYPE, new SpanNode.SpanNodeCreator());
-    registeredTextNodes.put(ImgNode.NODE_TYPE, new ImgNode.ImgNodeCreator());
-    registeredTextNodes.put(ANode.NODE_TYPE, new ANode.ANodeCreator());
-  }
-
-  public static void registerTextNode(String text, RichTextNodeCreator type) {
-    registeredTextNodes.put(text, type);
-  }
-
-  @Nullable
-  static RichTextNode createRichTextNode(@NonNull Context context, @NonNull String instanceId,
-      @NonNull String componentRef, @Nullable JSONObject jsonObject) {
-    RichTextNode instance = null;
-    try {
-      if (jsonObject != null) {
-        instance = registeredTextNodes.get(jsonObject.getString(RichTextNode.TYPE))
-            .createRichTextNode(context, instanceId, componentRef);
-        instance.parse(context, instanceId, componentRef, jsonObject);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("Richtext", WXLogUtils.getStackTrace(e));
-      instance = null;
-    }
-    return instance;
-  }
-  public static RichTextNode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
-                                         String nodeType,Map<String,String> styles,Map<String,String> attrs){
-    RichTextNode instance;
-    try{
-      instance = registeredTextNodes.get(nodeType).createRichTextNode(context,instanceId,componentRef,ref,styles,attrs);
-    }catch (Exception e){
-      WXLogUtils.e("Richtext", WXLogUtils.getStackTrace(e));
-      instance = null;
-    }
-    return instance;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/SpanNode.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/SpanNode.java
deleted file mode 100755
index dc48c1e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/node/SpanNode.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.node;
-
-import android.content.Context;
-import android.support.v4.util.ArrayMap;
-import android.text.SpannableStringBuilder;
-
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.TextDecorationSpan;
-import com.taobao.weex.dom.WXStyle;
-
-import java.util.ArrayList;
-import java.util.Map;
-
-class SpanNode extends RichTextNode {
-
-  static class SpanNodeCreator implements RichTextNodeCreator<SpanNode> {
-
-    @Override
-    public SpanNode createRichTextNode(Context context, String instanceId, String componentRef) {
-      return new SpanNode(context, instanceId, componentRef);
-    }
-
-    @Override
-    public SpanNode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
-                                       Map<String,Object> styles, Map<String,Object> attrs){
-      return new SpanNode(context,instanceId,componentRef,ref,styles,attrs);
-    }
-  }
-
-  public static final String NODE_TYPE = "span";
-
-  private SpanNode(Context context, String instanceId, String componentRef) {
-    super(context, instanceId, componentRef);
-  }
-  private SpanNode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles,Map<String,Object> attrs) {
-    super(context, instanceId, componentRef, ref, styles, attrs);
-  }
-
-  @Override
-  public String toString() {
-    if (attr == null || !attr.containsKey(Constants.Name.VALUE)) {
-      return "";
-    } else {
-      return attr.get(Constants.Name.VALUE).toString();
-    }
-  }
-
-  @Override
-  protected boolean isInternalNode() {
-    return true;
-  }
-
-  @Override
-  protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
-    super.updateSpans(spannableStringBuilder, level);
-    spannableStringBuilder.setSpan(new TextDecorationSpan(WXStyle.getTextDecoration(style)), 0,
-        spannableStringBuilder.length(), createSpanFlag(level));
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ASpan.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ASpan.java
deleted file mode 100644
index 8f5dd72..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ASpan.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.span;
-
-import android.text.TextPaint;
-import android.text.style.ClickableSpan;
-import android.view.View;
-import com.taobao.weex.utils.ATagUtil;
-
-public class ASpan extends ClickableSpan {
-
-  private String mInstanceId, mURL;
-
-  public ASpan(String instanceId, String url) {
-    mInstanceId = instanceId;
-    mURL = url;
-  }
-
-  @Override
-  public void onClick(View widget) {
-    ATagUtil.onClick(widget, mInstanceId, mURL);
-  }
-
-  /**
-   Override super method and do nothing. As no default color or text-decoration is needed.
-   */
-  @Override
-  public void updateDrawState(TextPaint ds) {
-
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ImgSpan.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ImgSpan.java
deleted file mode 100644
index f3bdc3c..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ImgSpan.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.span;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.text.style.ReplacementSpan;
-import android.view.View;
-
-import com.taobao.weex.adapter.IDrawableLoader;
-
-
-public class ImgSpan extends ReplacementSpan implements IDrawableLoader.StaticTarget {
-
-  private int width, height;
-  private Drawable mDrawable;
-  private View mView;
-
-  public ImgSpan(int width, int height) {
-    this.width = width;
-    this.height = height;
-  }
-
-  /**
-   * Mostly copied from
-   *
-   * {@link android.text.style.DynamicDrawableSpan#getSize(Paint, CharSequence, int, int, Paint.FontMetricsInt)},
-   * but not use Drawable to calculate size;
-   */
-  @Override
-  public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
-    if (fm != null) {
-      fm.ascent = -height;
-      fm.descent = 0;
-
-      fm.top = fm.ascent;
-      fm.bottom = 0;
-    }
-    return width;
-  }
-
-  /**
-   * Mostly copied from
-   * {@link android.text.style.DynamicDrawableSpan#draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)},
-   * except for vertical alignment.
-   */
-  @Override
-  public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
-    if (mDrawable != null) {
-      canvas.save();
-      int transY = bottom - mDrawable.getBounds().bottom;
-      transY -= paint.getFontMetricsInt().descent;
-      canvas.translate(x, transY);
-      mDrawable.draw(canvas);
-      canvas.restore();
-    }
-  }
-
-  @Override
-  public void setDrawable(Drawable drawable, boolean resetBounds) {
-    mDrawable = drawable;
-    if(resetBounds) {
-      mDrawable.setBounds(0, 0, width, height);
-    }
-    setCallback();
-    mDrawable.invalidateSelf();
-  }
-
-  public void setView(View view) {
-    mView = view;
-    setCallback();
-  }
-
-  private void setCallback() {
-    if (mDrawable != null && mView != null) {
-      mDrawable.setCallback(mView);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ItemClickSpan.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ItemClickSpan.java
deleted file mode 100644
index c7146da..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/richtext/span/ItemClickSpan.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.richtext.span;
-
-
-import android.text.style.ClickableSpan;
-import android.view.View;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.ui.component.richtext.node.RichTextNode;
-import com.taobao.weex.utils.WXDataStructureUtil;
-import java.util.Map;
-
-public class ItemClickSpan extends ClickableSpan {
-
-  private final String mPseudoRef;
-  private final String mInstanceId;
-  private final String mComponentRef;
-
-  public ItemClickSpan(String instanceId, String componentRef, String pseudoRef) {
-    this.mPseudoRef = pseudoRef;
-    this.mInstanceId = instanceId;
-    this.mComponentRef = componentRef;
-  }
-
-  @Override
-  public void onClick(View widget) {
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
-    if (instance != null && !instance.isDestroy()) {
-      Map<String, Object> param = WXDataStructureUtil.newHashMapWithExpectedSize(1);
-      param.put(RichTextNode.PSEUDO_REF, mPseudoRef);
-      instance.fireEvent(mComponentRef, RichTextNode.ITEM_CLICK, param);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/config/AutoScanConfigRegister.java b/android/sdk/src/main/java/com/taobao/weex/ui/config/AutoScanConfigRegister.java
deleted file mode 100644
index a6cbae0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/config/AutoScanConfigRegister.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.config;
-
-import android.content.res.AssetManager;
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.JavascriptInvokable;
-import com.taobao.weex.utils.WXFileUtils;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.io.IOException;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * Created by furture on 2018/2/7.
- */
-
-public class AutoScanConfigRegister {
-
-    private static long scanDelay = 0;
-
-    public static final  String TAG  = "WeexScanConfigRegister";
-
-
-    /**
-     * auto scan config files and do auto config from files, none need center register
-     * */
-    public static void doScanConfig(){
-        if(scanDelay > 0){
-            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    doScanConfigAsync();
-                }
-            }, scanDelay);
-        }else{
-            doScanConfigAsync();
-        }
-    }
-
-    public static void doScanConfigAsync(){
-        Thread thread = new Thread(new Runnable() {
-            @Override
-            public void run() {
-                doScanConfigSync();
-            }
-        });
-        thread.setName("AutoScanConfigRegister");
-        thread.start();
-    }
-
-    private static void doScanConfigSync(){
-        if(WXEnvironment.sApplication == null){
-            return;
-        }
-        try{
-            AssetManager assetManager = WXEnvironment.sApplication.getApplicationContext().getAssets();
-
-            String[] configFiles = new String[0];
-            try {
-                configFiles = assetManager.list("");
-            } catch (IOException e) {
-                WXLogUtils.e(TAG, e);
-            }
-            if(configFiles == null || configFiles.length == 0){
-                return;
-            }
-            for(String configFile : configFiles){
-                if(TextUtils.isEmpty(configFile)){
-                    continue;
-                }
-                if(configFile.startsWith("weex_config_") && configFile.endsWith(".json")){
-                    String name = configFile;
-                    if(TextUtils.isEmpty(name)){
-                        return;
-                    }
-                    try {
-                        String config = WXFileUtils.loadAsset(name, WXEnvironment.getApplication());
-                        if (TextUtils.isEmpty(config)) {
-                            continue;
-                        }
-                        if (WXEnvironment.isApkDebugable()) {
-                            WXLogUtils.d(TAG, configFile + " find config " + config);
-                        }
-                        JSONObject object = JSON.parseObject(config);
-                        if (object.containsKey("modules")) {
-                            JSONArray array = object.getJSONArray("modules");
-                            for (int i = 0; i < array.size(); i++) {
-                                ConfigModuleFactory configModuleFactory = ConfigModuleFactory.fromConfig(array.getJSONObject(i));
-                                if (configModuleFactory == null) {
-                                    continue;
-                                }
-                                WXSDKEngine.registerModule(configModuleFactory.getName(), configModuleFactory, false);
-                            }
-                        }
-
-                        if (object.containsKey("components")) {
-                            JSONArray array = object.getJSONArray("components");
-                            for (int i = 0; i < array.size(); i++) {
-                                ConfigComponentHolder configComponentHolder = ConfigComponentHolder.fromConfig(array.getJSONObject(i));
-                                if (configComponentHolder == null) {
-                                    return;
-                                }
-                                WXSDKEngine.registerComponent(configComponentHolder, configComponentHolder.isAppendTree(), configComponentHolder.getType());
-                            }
-                        }
-                    }catch (Throwable e){
-                        WXLogUtils.e(TAG, e);
-                    }
-                }
-            }
-        }catch (Exception eout){
-            WXLogUtils.e(TAG, eout);
-        }
-    }
-
-    public static void setScanDelay(long scanDelay) {
-        AutoScanConfigRegister.scanDelay = scanDelay;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/config/ConfigComponentHolder.java b/android/sdk/src/main/java/com/taobao/weex/ui/config/ConfigComponentHolder.java
deleted file mode 100644
index 7a9948d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/config/ConfigComponentHolder.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.config;
-
-import android.text.TextUtils;
-import android.util.Pair;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.ui.ComponentCreator;
-import com.taobao.weex.ui.IFComponentHolder;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.Map;
-
-/**
- * Created by furture on 2018/2/7.
- */
-public class ConfigComponentHolder implements IFComponentHolder {
-
-
-    public static final String TAG = AutoScanConfigRegister.TAG;
-    private Map<String, Invoker> mPropertyInvokers;
-    private Map<String, Invoker> mMethodInvokers;
-
-    private ClassLoader mClassLoader;
-
-    private String mType;
-    private boolean mAppendTree;
-    private String mClassName;
-    private String[] methods;
-    private Class mClass;
-
-    public ConfigComponentHolder(String mType, boolean mAppendTree, String mClassName, String[] methods) {
-        this.mType = mType;
-        this.mAppendTree = mAppendTree;
-        this.mClassName = mClassName;
-        this.methods = methods;
-    }
-
-    @Override
-    public void loadIfNonLazy() {
-    }
-
-    private synchronized boolean generate(){
-        if(mClass == null){
-            return false;
-        }
-
-        Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = SimpleComponentHolder.getMethods(mClass);
-        mPropertyInvokers = methodPair.first;
-        mMethodInvokers = methodPair.second;
-        return true;
-    }
-
-
-
-    @Override
-    public synchronized WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-        if(mClass == null || mClassLoader != instance.getContext().getClassLoader()){
-            mClass = WXSDKManager.getInstance().getClassLoaderAdapter().getComponentClass(mType, mClassName, instance);
-            mClassLoader = instance.getContext().getClassLoader();
-        }
-        ComponentCreator creator = new SimpleComponentHolder.ClazzComponentCreator(mClass);
-        WXComponent component = creator.createInstance(instance, parent, basicComponentData);
-
-        component.bindHolder(this);
-        return component;
-    }
-
-    @Override
-    public synchronized Invoker getPropertyInvoker(String name){
-        if (mPropertyInvokers == null && !generate()) {
-            return null;
-        }
-
-        return mPropertyInvokers.get(name);
-    }
-
-    @Override
-    public Invoker getMethodInvoker(String name) {
-        if(mMethodInvokers == null && !generate()){
-            return null;
-        }
-        return mMethodInvokers.get(name);
-    }
-
-    @Override
-    public String[] getMethods() {
-        if(methods == null){
-            //generate failed
-            return new String[0];
-        }
-        return methods;
-    }
-
-
-    public static final ConfigComponentHolder fromConfig(JSONObject config){
-        if(config == null){
-            return null;
-        }
-        try{
-            String type = config.getString("name");
-            boolean appendTree  = config.getBooleanValue("appendTree");
-            String className = config.getString("className");
-            JSONArray methods =  null;
-            if(config.containsKey("methods")) {
-                methods = config.getJSONArray("methods");
-            }
-            if(TextUtils.isEmpty(type) || TextUtils.isEmpty(className)){
-                return null;
-            }
-            String[]  arrays = new String[0];
-            if(methods != null){
-                arrays = new String[methods.size()];
-                methods.toArray(arrays);
-            }
-            if(WXEnvironment.isApkDebugable()){
-                WXLogUtils.d(TAG, "resolve component " + type + " className " + className +  " methods " + methods);
-            }
-            return new ConfigComponentHolder(type, appendTree, className, arrays);
-        }catch (Exception e){
-            WXLogUtils.e(TAG, e);
-            return null;
-        }
-
-    }
-
-    public boolean isAppendTree() {
-        return mAppendTree;
-    }
-
-    public String getType() {
-        return mType;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/config/ConfigModuleFactory.java b/android/sdk/src/main/java/com/taobao/weex/ui/config/ConfigModuleFactory.java
deleted file mode 100644
index 4b8f973..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/config/ConfigModuleFactory.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.config;
-
-import android.text.TextUtils;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.bridge.MethodInvoker;
-import com.taobao.weex.bridge.ModuleFactory;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.common.WXModuleAnno;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by furture on 2018/2/7.
- */
-
-public class ConfigModuleFactory<T extends WXModule> implements ModuleFactory<T> {
-
-    public static final String TAG = AutoScanConfigRegister.TAG;
-
-    private String mName;
-    private String mClassName;
-    private String[] methods;
-    private Class<T> mClazz;
-    private Map<String, Invoker> mMethodMap;
-
-    private ClassLoader mClassLoader;
-
-    public ConfigModuleFactory(String mName, String mClassName, String[] methods) {
-        this.mName = mName;
-        this.mClassName = mClassName;
-        this.methods = methods;
-    }
-
-    @Override
-    public String[] getMethods() {
-        if(methods == null){
-            return new String[0];
-        }
-        return methods;
-    }
-
-    @Override
-    public Invoker getMethodInvoker(String name) {
-        if (mMethodMap == null) {
-            generateMethodMap();
-        }
-        return mMethodMap.get(name);
-    }
-
-    @Override
-    public T buildInstance() throws IllegalAccessException, InstantiationException {
-        if(mClazz == null){
-            mClazz = (Class<T>) WXSDKManager.getInstance().getClassLoaderAdapter().getModuleClass(mName, mClassName, WXEnvironment.getApplication().getApplicationContext());
-        }
-        return mClazz.newInstance();
-    }
-
-    public T buildInstance(WXSDKInstance instance) throws IllegalAccessException, InstantiationException {
-        if(instance == null){
-            return buildInstance();
-        }
-        if(mClazz == null || mClassLoader != instance.getContext().getClassLoader()){
-            mClazz = (Class<T>) WXSDKManager.getInstance().getClassLoaderAdapter().getModuleClass(mName, mClassName, instance.getContext());
-            mClassLoader = instance.getContext().getClassLoader();
-        }
-        return mClazz.newInstance();
-    }
-
-
-    private void generateMethodMap() {
-        if(WXEnvironment.isApkDebugable()) {
-             WXLogUtils.d(TAG, "extractMethodNames:" + mClazz.getSimpleName());
-        }
-        HashMap<String, Invoker> methodMap = new HashMap<>();
-        try {
-            for (Method method : mClazz.getMethods()) {
-                // iterates all the annotations available in the method
-                for (Annotation anno : method.getDeclaredAnnotations()) {
-                    if (anno != null) {
-                        if(anno instanceof JSMethod) {
-                            JSMethod methodAnnotation = (JSMethod) anno;
-                            String name = JSMethod.NOT_SET.equals(methodAnnotation.alias())? method.getName():methodAnnotation.alias();
-                            methodMap.put(name, new MethodInvoker(method, methodAnnotation.uiThread()));
-                            break;
-                        }else if(anno instanceof WXModuleAnno) {
-                            WXModuleAnno methodAnnotation = (WXModuleAnno)anno;
-                            methodMap.put(method.getName(), new MethodInvoker(method,methodAnnotation.runOnUIThread()));
-                            break;
-                        }
-                    }
-                }
-            }
-        } catch (Throwable e) {
-            WXLogUtils.e("[WXModuleManager] extractMethodNames:", e);
-        }
-        mMethodMap = methodMap;
-    }
-
-
-    public static ConfigModuleFactory fromConfig(JSONObject config){
-        try{
-            if(config == null){
-                return null;
-            }
-
-            String name = config.getString("name");
-            String className = config.getString("className");
-            JSONArray methods = config.getJSONArray("methods");
-            if(TextUtils.isEmpty(name) || TextUtils.isEmpty(className)){
-                return null;
-            }
-            String[]  arrays = new String[methods.size()];
-            if(WXEnvironment.isApkDebugable()){
-                WXLogUtils.d(TAG, " resolve module " + name + " className " + className +  " methods " + methods);
-            }
-            return new ConfigModuleFactory(name, className, methods.toArray(arrays));
-        }catch (Exception e){
-             WXLogUtils.e(TAG, e);
-             return null;
-        }
-    }
-
-    public String getName() {
-        return mName;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java
deleted file mode 100644
index 823da47..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat;
-
-
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-
-import com.taobao.weex.ui.flat.widget.Widget;
-
-@RestrictTo(Scope.LIBRARY)
-public interface FlatComponent<T extends Widget> {
-
-  boolean promoteToView(boolean checkAncestor);
-
-  @NonNull
-  T getOrCreateFlatWidget();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java
deleted file mode 100644
index 16f1d62..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat;
-
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import android.view.View;
-
-import com.taobao.weex.common.Constants.Name;
-import com.taobao.weex.common.Destroyable;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.flat.widget.AndroidViewWidget;
-import com.taobao.weex.ui.flat.widget.Widget;
-
-import java.util.Map;
-import java.util.Map.Entry;
-
-//TODO The constructor of FlatGUIContext should have a flag decide whether to enable flagGUI.
-
-@RestrictTo(Scope.LIBRARY)
-public class FlatGUIContext implements Destroyable {
-
-  private Map<WXComponent, WidgetContainer> mWidgetRegistry = new ArrayMap<>();
-  private Map<WXComponent, AndroidViewWidget> mViewWidgetRegistry = new ArrayMap<>();
-  private Map<Widget, WXComponent> widgetToComponent = new ArrayMap<>();
-
-  public boolean isFlatUIEnabled(WXComponent component) {
-    return false;
-  }
-
-  public void register(@NonNull WXComponent descendant, @NonNull WidgetContainer ancestor) {
-    if (!(ancestor instanceof FlatComponent) ||
-            ((FlatComponent) ancestor).promoteToView(true)) {
-      mWidgetRegistry.put(descendant, ancestor);
-    }
-  }
-
-  public void register(@NonNull WXComponent component, @NonNull AndroidViewWidget viewWidget) {
-    mViewWidgetRegistry.put(component, viewWidget);
-  }
-
-  public void register(@NonNull Widget widget, @NonNull WXComponent component) {
-    widgetToComponent.put(widget, component);
-  }
-
-  public
-  @Nullable
-  WidgetContainer getFlatComponentAncestor(@NonNull WXComponent flatWidget) {
-    return mWidgetRegistry.get(flatWidget);
-  }
-
-  public
-  @Nullable
-  AndroidViewWidget getAndroidViewWidget(@NonNull WXComponent component) {
-    return mViewWidgetRegistry.get(component);
-  }
-
-  public boolean promoteToView(@NonNull WXComponent component, boolean checkAncestor,
-                               @NonNull Class<? extends WXComponent<?>> expectedClass) {
-    return !isFlatUIEnabled(component) ||
-            !expectedClass.equals(component.getClass()) ||
-            TextUtils.equals(component.getRef(), WXComponent.ROOT) ||
-            (checkAncestor && getFlatComponentAncestor(component) == null) ||
-            checkComponent(component);
-  }
-
-  public
-  @Nullable
-  View getWidgetContainerView(Widget widget) {
-    WXComponent component, ancestor;
-    View ret = null;
-    if ((component = getComponent(widget)) != null) {
-      if ((ancestor = getFlatComponentAncestor(component)) != null) {
-        ret = ancestor.getHostView();
-      }
-    }
-    return ret;
-  }
-
-  @Override
-  @RestrictTo(Scope.LIBRARY)
-  public void destroy() {
-    widgetToComponent.clear();
-
-    for (Entry<WXComponent, AndroidViewWidget> entry : mViewWidgetRegistry.entrySet()) {
-      entry.getValue().destroy();
-    }
-    mViewWidgetRegistry.clear();
-
-    for (Entry<WXComponent, WidgetContainer> entry : mWidgetRegistry.entrySet()) {
-      entry.getValue().unmountFlatGUI();
-    }
-    mWidgetRegistry.clear();
-  }
-
-  private @Nullable
-  WXComponent getComponent(@NonNull Widget widget) {
-    return widgetToComponent.get(widget);
-  }
-
-  private boolean checkComponent(@NonNull WXComponent component) {
-    boolean ret = false;
-    if (component != null) {
-      WXStyle style = component.getStyles();
-      WXAttr attr = component.getAttrs();
-      if (style.containsKey(Name.OPACITY) ||
-              style.containsKey(Name.TRANSFORM) ||
-              style.containsKey(Name.VISIBILITY) ||
-              attr.containsKey(Name.ELEVATION) ||
-              attr.containsKey(Name.ARIA_HIDDEN) ||
-              attr.containsKey(Name.ARIA_LABEL) ||
-              attr.containsKey(WXComponent.PROP_FIXED_SIZE) ||
-              attr.containsKey(Name.DISABLED) ||
-              style.isFixed() ||
-              style.isSticky() ||
-              !style.getPesudoStyles().isEmpty() ||
-              component.getEvents().size() > 0) {
-        ret = true;
-      }
-    }
-    return ret;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java
deleted file mode 100644
index 0946800..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat;
-
-
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.util.Pair;
-import android.view.ViewGroup;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.action.BasicComponentData;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.ui.flat.widget.AndroidViewWidget;
-import com.taobao.weex.ui.flat.widget.Widget;
-
-import java.util.LinkedList;
-import java.util.List;
-
-@RestrictTo(Scope.LIBRARY)
-public abstract class WidgetContainer<T extends ViewGroup> extends WXVContainer<T> {
-
-  protected List<Widget> widgets;
-
-  public WidgetContainer(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
-    super(instance, parent, basicComponentData);
-  }
-
-  protected abstract void mountFlatGUI();
-
-  protected abstract void unmountFlatGUI();
-
-  public boolean intendToBeFlatContainer() {
-    return false;
-  }
-
-  @Override
-  public void createChildViewAt(int index) {
-    if (intendToBeFlatContainer()) {
-      Pair<WXComponent, Integer> ret = rearrangeIndexAndGetChild(index);
-      if (ret.first != null) {
-        WXComponent child = ret.first;
-        Widget flatChild;
-        FlatGUIContext uiImp = getInstance().getFlatUIContext();
-        WidgetContainer parent = uiImp.getFlatComponentAncestor(this);
-        if (parent == null || uiImp.getAndroidViewWidget(this) != null) {
-          parent = this;
-        }
-        uiImp.register(child, parent);
-
-        if (child instanceof FlatComponent && !((FlatComponent) child).promoteToView(false)) {
-          flatChild = ((FlatComponent) child).getOrCreateFlatWidget();
-        } else {
-          flatChild = new AndroidViewWidget(uiImp);
-          uiImp.register(child, (AndroidViewWidget) flatChild);
-          child.createView();
-          ((AndroidViewWidget) flatChild).setContentView(child.getHostView());
-          //TODO Use a sort algorithm to decide the childIndex of AndroidViewWidget
-          parent.addSubView(child.getHostView(), -1);
-        }
-        uiImp.register(flatChild, child);
-        addFlatChild(flatChild, ret.second);
-      }
-    } else {
-      super.createChildViewAt(index);
-    }
-  }
-
-  private void addFlatChild(Widget widget, int index) {
-    if(widgets == null){
-      widgets = new LinkedList<>();
-    }
-    if (index >= widgets.size()) {
-      widgets.add(widget);
-    } else {
-      widgets.add(index, widget);
-    }
-    //TODO do a partial update, not mount the whole flatContainer.
-    mountFlatGUI();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java
deleted file mode 100644
index ad72054..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat.widget;
-
-
-import android.graphics.Canvas;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.view.View;
-
-import com.taobao.weex.common.Destroyable;
-import com.taobao.weex.ui.flat.FlatGUIContext;
-
-@RestrictTo(Scope.LIBRARY)
-public class AndroidViewWidget extends BaseWidget implements Destroyable {
-
-  private @Nullable
-  View mView;
-
-  public AndroidViewWidget(@NonNull FlatGUIContext context) {
-    super(context);
-  }
-
-  public void setContentView(@Nullable View view) {
-    this.mView = view;
-  }
-
-  @Override
-  public void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset) {
-    if (mView != null) {
-      mView.setPadding(leftOffset, topOffset, rightOffset, bottomOffset);
-      invalidate();
-    }
-  }
-
-  @Override
-  public void onDraw(@NonNull Canvas canvas) {
-    if (mView != null) {
-      mView.draw(canvas);
-    }
-  }
-
-  @Override
-  public void invalidate() {
-    super.invalidate();
-    if (mView != null) {
-      mView.invalidate();
-    }
-  }
-
-  public @Nullable
-  View getView() {
-    return mView;
-  }
-
-  @Override
-  public void destroy() {
-    if (mView != null) {
-      mView = null;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java
deleted file mode 100644
index 09cd14a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat.widget;
-
-
-import android.graphics.Canvas;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.view.View;
-import com.taobao.weex.ui.flat.FlatGUIContext;
-import com.taobao.weex.ui.view.border.BorderDrawable;
-import com.taobao.weex.utils.WXViewUtils;
-
-@RestrictTo(Scope.LIBRARY)
-abstract class BaseWidget implements Widget {
-
-  //TODO Reconsider the field parameter in this class and the operation during draw(); Make a CPU/Memory balance.
-  //TODO use float to avoid 1px problem
-  private BorderDrawable backgroundBorder;
-  private int leftOffset, topOffset, rightOffset, bottomOffset;
-  private Rect borderBox = new Rect();
-  private Point offsetOfContainer = new Point();
-  private final @NonNull
-  FlatGUIContext context;
-
-  BaseWidget(@NonNull FlatGUIContext context){
-    this.context = context;
-  }
-
-  @Override
-  public void setLayout(int width, int height, int left, int right, int top, int bottom, Point offset) {
-    this.offsetOfContainer = offset;
-    borderBox.set(left, top, left + width, top + height);
-    if (backgroundBorder != null) {
-      setBackgroundAndBorder(backgroundBorder);
-    }
-    invalidate();
-  }
-
-  @Override
-  public void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset) {
-    this.leftOffset = leftOffset;
-    this.topOffset = topOffset;
-    this.rightOffset = rightOffset;
-    this.bottomOffset = bottomOffset;
-    invalidate();
-  }
-
-  @Override
-  public void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder) {
-    //TODO Change the code of BorderDrawable is more appropriate as it draws the borderLine from (0,0) not from getBounds
-    //TODO If the above is finished, no more traslate in draw in needed, only clip is enough.
-    this.backgroundBorder = backgroundBorder;
-    Rect backgroundBox = new Rect(borderBox);
-    backgroundBox.offset(-borderBox.left, -borderBox.top);
-    backgroundBorder.setBounds(backgroundBox);
-    setCallback(backgroundBorder);
-    invalidate();
-  }
-
-  @NonNull
-  @Override
-  public final Point getLocInFlatContainer() {
-    return offsetOfContainer;
-  }
-
-  @Nullable
-  @Override
-  public final BorderDrawable getBackgroundAndBorder() {
-    return backgroundBorder;
-  }
-
-  @NonNull
-  @Override
-  public final Rect getBorderBox() {
-    return borderBox;
-  }
-
-  @Override
-  public final void draw(@NonNull Canvas canvas) {
-    canvas.save();
-    WXViewUtils.clipCanvasWithinBorderBox(this, canvas);
-    canvas.translate(borderBox.left, borderBox.top);
-    if (backgroundBorder != null) {
-      backgroundBorder.draw(canvas);
-    }
-    canvas.clipRect(leftOffset, topOffset, borderBox.width()-rightOffset, borderBox.height() - bottomOffset);
-    canvas.translate(leftOffset, topOffset);
-    onDraw(canvas);
-    canvas.restore();
-  }
-
-  protected void invalidate() {
-    Rect dirtyRegion = new Rect(borderBox);
-    dirtyRegion.offset(offsetOfContainer.x, offsetOfContainer.y);
-    View widgetContainer;
-    if (context != null && (widgetContainer = context.getWidgetContainerView(this)) != null) {
-      widgetContainer.invalidate(dirtyRegion);
-    }
-  }
-
-  protected void setCallback(@NonNull Drawable drawable) {
-    View widgetContainer;
-    if (context != null && (widgetContainer = context.getWidgetContainerView(this)) != null) {
-      drawable.setCallback(widgetContainer);
-    }
-  }
-}
-
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java
deleted file mode 100644
index fee01b9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat.widget;
-
-
-import android.graphics.Canvas;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import android.text.Layout;
-
-import com.taobao.weex.ui.flat.FlatGUIContext;
-
-@RestrictTo(Scope.LIBRARY)
-public class TextWidget extends BaseWidget {
-
-  private Layout mLayout;
-
-  public TextWidget(@NonNull FlatGUIContext context) {
-    super(context);
-  }
-
-  @Override
-  public void onDraw(@NonNull Canvas canvas) {
-    if (mLayout != null) {
-      mLayout.draw(canvas);
-    }
-  }
-
-  public void updateTextDrawable(Layout layout) {
-    this.mLayout = layout;
-    invalidate();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java
deleted file mode 100644
index ac9eb6f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat.widget;
-
-
-import android.graphics.Canvas;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-
-import com.taobao.weex.ui.view.border.BorderDrawable;
-
-@RestrictTo(Scope.LIBRARY)
-public interface Widget {
-
-  public static final String TAG = "Widget";
-
-  void draw(@NonNull Canvas canvas);
-
-  void onDraw(@NonNull Canvas canvas);
-
-  void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder);
-
-  void setLayout(int width, int height, int left, int right, int top, int bottom, Point offset);
-
-  void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset);
-
-  @NonNull
-  Point getLocInFlatContainer();
-
-  @Nullable
-  BorderDrawable getBackgroundAndBorder();
-
-  @NonNull
-  Rect getBorderBox();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java
deleted file mode 100644
index 942a4b1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.flat.widget;
-
-
-import android.graphics.Canvas;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-
-import com.taobao.weex.ui.flat.FlatGUIContext;
-
-import java.util.LinkedList;
-import java.util.List;
-
-@RestrictTo(Scope.LIBRARY)
-public class WidgetGroup extends BaseWidget {
-
-  private List<Widget> mChildren = new LinkedList<>();
-
-  public WidgetGroup(@NonNull FlatGUIContext context) {
-    super(context);
-  }
-
-  public void replaceAll(@NonNull List<Widget> widgets) {
-    mChildren = widgets;
-    invalidate();
-  }
-
-  public List<Widget> getChildren() {
-    return mChildren;
-  }
-
-  @Override
-  public void onDraw(@NonNull Canvas canvas) {
-    for (Widget child : mChildren) {
-      child.draw(canvas);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/ConsoleLogModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/ConsoleLogModule.java
deleted file mode 100644
index 3db7cef..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/ConsoleLogModule.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.utils.LogLevel;
-import java.util.Map;
-
-
-public class ConsoleLogModule extends WXModule {
-
-  @JSMethod(uiThread = false)
-  public void switchLogLevel(@Nullable String logLevel, @Nullable JSCallback callback) {
-    LogLevel logLevelEnum = getLogLevel(logLevel);
-    Map<String, String> ret = new ArrayMap<>();
-    if (logLevelEnum != null) {
-      WXEnvironment.sLogLevel = logLevelEnum;
-      WXBridgeManager.getInstance().setLogLevel(WXEnvironment.sLogLevel.getValue(),WXEnvironment.isPerf());
-      ret.put("status", "success");
-    } else {
-      ret.put("status", "failure");
-    }
-
-    if (callback != null) {
-      callback.invoke(ret);
-    }
-
-  }
-
-  @JSMethod(uiThread = false)
-  public void setPerfMode(@Nullable String on) {
-    WXEnvironment.isPerf = "true".equals(on);
-    WXBridgeManager.getInstance().setLogLevel(WXEnvironment.sLogLevel.getValue(),WXEnvironment.isPerf());
-  }
-
-  private @Nullable LogLevel getLogLevel(@Nullable String logLevel) {
-    LogLevel logLevelEnum = null;
-    if(!TextUtils.isEmpty(logLevel)){
-      switch (logLevel){
-        case "off":
-          logLevelEnum = LogLevel.OFF;
-          break;
-        case "error":
-          logLevelEnum = LogLevel.ERROR;
-          break;
-        case "warning":
-          logLevelEnum = LogLevel.WARN;
-          break;
-        case "info":
-          logLevelEnum = LogLevel.INFO;
-          break;
-        case "debug":
-          logLevelEnum = LogLevel.DEBUG;
-          break;
-      }
-    }
-    return logLevelEnum;
-  }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDeviceInfoModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDeviceInfoModule.java
deleted file mode 100644
index 02392c6..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDeviceInfoModule.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.util.HashMap;
-
-public class WXDeviceInfoModule extends WXModule {
-    
-    @JSMethod(uiThread = false)
-    public void enableFullScreenHeight(final JSCallback callback,JSONObject extend){
-        if(mWXSDKInstance != null) {
-            mWXSDKInstance.setEnableFullScreenHeight(true);
-            if(callback != null) {
-                long fullScreenHeight = WXViewUtils.getScreenHeight(mWXSDKInstance.getInstanceId());
-                HashMap<String, String> ret = new HashMap();
-                ret.put("fullScreenHeight", String.valueOf(fullScreenHeight));
-                callback.invoke(ret);
-            }
-
-        }
-
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDomModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDomModule.java
deleted file mode 100644
index 08ce054..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDomModule.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import android.support.annotation.RestrictTo;
-import android.support.annotation.RestrictTo.Scope;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.dom.binding.JSONUtils;
-import com.taobao.weex.ui.action.ActionAddRule;
-import com.taobao.weex.ui.action.ActionGetComponentRect;
-import com.taobao.weex.ui.action.ActionGetLayoutDirection;
-import com.taobao.weex.ui.action.ActionInvokeMethod;
-import com.taobao.weex.ui.action.GraphicActionBatchBegin;
-import com.taobao.weex.ui.action.GraphicActionBatchEnd;
-import com.taobao.weex.ui.action.GraphicActionScrollToElement;
-import com.taobao.weex.ui.action.UpdateComponentDataAction;
-import com.taobao.weex.utils.WXLogUtils;
-
-/**
- * <p>
- * Module class for dom operation.
- * </p>
- * <p>
- *   This module is work different with other regular module, method is invoked directly, without reflection.
- * </p>
- *
- * <p>
- *  This class is for internal purpose,
- *  please don't use it directly unless you know what you are doing.
- * </p>
- */
-@RestrictTo(Scope.LIBRARY_GROUP)
-public class WXDomModule extends WXModule {
-
-  /** package **/
-  public static final String SCROLL_TO_ELEMENT = "scrollToElement";
-  public static final String ADD_RULE = "addRule";
-  public static final String GET_COMPONENT_RECT = "getComponentRect";
-  public static final String GET_COMPONENT_DIRECTION = "getLayoutDirection";
-  public static final String WXDOM = "dom";
-  public static final String INVOKE_METHOD = "invokeMethod";
-
-  public static final String UPDATE_COMPONENT_DATA = "updateComponentData";
-
-  public static final String BATCH_BEGIN = "beginBatchMark";
-  public static final String BATCH_END = "endBatchMark";
-
-  /**
-   * Methods expose to js. Every method which will be called in js should add to this array.
-   */
-  public static final String[] METHODS = {SCROLL_TO_ELEMENT, ADD_RULE, GET_COMPONENT_RECT,
-      INVOKE_METHOD, GET_COMPONENT_DIRECTION, BATCH_BEGIN, BATCH_END};
-
-  public WXDomModule(WXSDKInstance instance){
-    mWXSDKInstance = instance;
-  }
-
-  public void callDomMethod(JSONObject task, long... parseNanos) {
-    if (task == null) {
-      return;
-    }
-    String method = (String) task.get(WXBridgeManager.METHOD);
-    JSONArray args = (JSONArray) task.get(WXBridgeManager.ARGS);
-    callDomMethod(method,args,parseNanos);
-  }
-
-  public Object callDomMethod(String method, JSONArray args, long... parseNanos) {
-
-    if (method == null) {
-      return null;
-    }
-
-    try {
-      switch (method) {
-        case GET_COMPONENT_DIRECTION: {
-          if(args == null){
-            return null;
-          }
-          new ActionGetLayoutDirection(mWXSDKInstance, args.getString(0), args.getString(1))
-                  .executeActionOnRender();
-          break;
-        }
-        case SCROLL_TO_ELEMENT:{
-          if (args == null) {
-            return null;
-          }
-          String ref = args.size() >= 1 ? args.getString(0) : null;
-          JSONObject options = args.size() >= 2 ? args.getJSONObject(1) : null;
-          new GraphicActionScrollToElement(mWXSDKInstance, ref, options)
-                  .executeActionOnRender();
-          break;
-        }
-        case ADD_RULE:{
-          if (args == null) {
-            return null;
-          }
-          new ActionAddRule(mWXSDKInstance.getInstanceId(), args.getString(0), args.getJSONObject(1))
-                  .executeAction();
-          break;
-        }
-        case GET_COMPONENT_RECT:{
-            if(args == null){
-                return null;
-            }
-            new ActionGetComponentRect(mWXSDKInstance, args.getString(0), args.getString(1))
-                    .executeActionOnRender();
-            break;
-        }
-        case INVOKE_METHOD: {
-          if(args == null){
-            return null;
-          }
-          // todo:no sure where the request com from
-          new ActionInvokeMethod(mWXSDKInstance.getInstanceId(), args.getString(0), args.getString(1), args.getJSONArray(2))
-                  .executeAction();
-          break;
-        }
-        case UPDATE_COMPONENT_DATA:
-          if(args == null || args.size() < 3){
-            return null;
-          }
-          new UpdateComponentDataAction(mWXSDKInstance, args.getString(0), JSONUtils.toJSON(args.get(1)), args.getString(2)).executeAction();
-          break;
-        case BATCH_BEGIN: {
-          if(args == null){
-            return null;
-          }
-          String ref = args.size() >= 1 ? args.getString(0) : null;
-          new GraphicActionBatchBegin(mWXSDKInstance, ref).executeActionOnRender();
-          break;
-        }
-        case BATCH_END: {
-          String ref = args.size() >= 1 ? args.getString(0) : null;
-          new GraphicActionBatchEnd(mWXSDKInstance, ref).executeActionOnRender();
-          break;
-        }
-        default:
-          WXLogUtils.e("Unknown dom action.");
-          break;
-      }
-
-      // todo TraceableAction
-//      if (WXTracing.isAvailable() && action instanceof TraceableAction) {
-//        String ref = null;
-//        String type = null;
-//        if (args.size() > 0) {
-//          if (args.size() >= 1) {
-//            if (args.get(0) instanceof String) {
-//              ref = args.getString(0);
-//            } else if (args.get(0) instanceof JSONObject) {
-//              ref = ((JSONObject) args.get(0)).getString("ref");
-//              type = ((JSONObject) args.get(0)).getString("type");
-//            }
-//          }
-//
-//          if (args.size() >= 2) {
-//            if (args.get(1) instanceof JSONObject) {
-//              ref = ((JSONObject) args.get(1)).getString("ref");
-//              type = ((JSONObject) args.get(1)).getString("type");
-//            }
-//          }
-//        }
-//        if (parseNanos != null && parseNanos.length == 1) {
-//          ((TraceableAction) action).mParseJsonNanos = parseNanos[0];
-//          ((TraceableAction) action).mStartMillis -= Stopwatch.nanosToMillis(parseNanos[0]);
-//        }
-//        ((TraceableAction) action).onStartDomExecute(mWXSDKInstance.getInstanceId(), method, ref, type, args.toJSONString());
-//      }
-    } catch (IndexOutOfBoundsException e) {
-      // no enougn args
-      e.printStackTrace();
-      WXLogUtils.e("Dom module call miss arguments.");
-    } catch (ClassCastException cce) {
-      WXLogUtils.e("Dom module call arguments format error!!");
-    }
-    return null;
-  }
-
-  public void invokeMethod(String ref, String method, JSONArray args){
-    if(ref == null || method == null){
-      return;
-    }
-
-    new ActionInvokeMethod(mWXSDKInstance.getInstanceId(), ref, method, args)
-            .executeAction();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXLocaleModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXLocaleModule.java
deleted file mode 100644
index 41a0c55..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXLocaleModule.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.LocaleList;
-import android.text.TextUtils;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.common.WXModule;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Created by moxun on 2017/9/26.
- * <p>
- * Ref: https://tools.ietf.org/html/bcp47
- */
-
-public class WXLocaleModule extends WXModule {
-
-  @JSMethod(uiThread = false)
-  public String getLanguageSync() {
-    return getLanguageImpl();
-  }
-
-  @JSMethod(uiThread = false)
-  public void getLanguage(JSCallback callback) {
-    callback.invoke(getLanguageImpl());
-  }
-
-  private String getLanguageImpl() {
-    Locale locale;
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-      locale = LocaleList.getDefault().get(0);
-    } else locale = Locale.getDefault();
-
-    String language = locale.getLanguage() + "-" + locale.getCountry();
-    return language;
-  }
-
-  @JSMethod(uiThread = false)
-  public List<String> getLanguages() {
-    String[] tags = getLanguageTags().split(",");
-    return Arrays.asList(tags);
-  }
-
-  @JSMethod(uiThread = false)
-  public void getLanguages(JSCallback callback) {
-    callback.invoke(getLanguageTags().split(","));
-  }
-
-  private String getLanguageTags() {
-    Context application = WXEnvironment.getApplication();
-    if (application != null) {
-      Resources res = application.getResources();
-      if (res != null) {
-        Configuration configuration = res.getConfiguration();
-        if (configuration != null) {
-          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            LocaleList localeList = configuration.getLocales();
-            return localeList.toLanguageTags();
-          } else {
-            Locale local = configuration.locale;
-            if (local != null) {
-              return toLanguageTag(local);
-            }
-          }
-        }
-      }
-    }
-    return "";
-  }
-
-  private String toLanguageTag(Locale locale) {
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-      return locale.toLanguageTag();
-    } else {
-      StringBuilder sb = new StringBuilder();
-      String language = locale.getLanguage();
-      String region = locale.getCountry();
-      sb.append(language);
-      if (!TextUtils.isEmpty(region)) {
-        sb.append("-").append(region);
-      }
-      return sb.toString();
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXMetaModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXMetaModule.java
deleted file mode 100644
index 04bb8e4..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXMetaModule.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import android.app.Application;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.text.TextUtils;
-import android.widget.Toast;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import java.net.URLDecoder;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by zhengshihan on 16/12/20.
- */
-
-public class WXMetaModule extends WXModule {
-
-    public static final String WIDTH = "width";
-    public static final String DEVICE_WIDTH = "device-width";
-
-    @JSMethod(uiThread = false)
-    public void setViewport(String param) {
-        if (!TextUtils.isEmpty(param)) {
-            try {
-                param = URLDecoder.decode(param, "utf-8");
-                JSONObject jsObj = JSON.parseObject(param);
-                Context cxt = mWXSDKInstance.getContext();
-                // todo maybe getString(WIDTH) is "device-height"
-                if (DEVICE_WIDTH.endsWith(jsObj.getString(WIDTH))) {
-                    int width = (int)(WXViewUtils.getScreenWidth(cxt)/WXViewUtils.getScreenDensity(cxt));
-                    mWXSDKInstance.setInstanceViewPortWidth(width,true);
-                    WXLogUtils.d("[WXMetaModule] setViewport success[device-width]=" + width);
-                } else {
-                    int width = jsObj.getInteger(WIDTH);
-                    if (width > 0) {
-                        mWXSDKInstance.setInstanceViewPortWidth(width,true);
-                    }
-                    WXLogUtils.d("[WXMetaModule] setViewport success[width]=" + width);
-                }
-            } catch (Exception e) {
-                WXLogUtils.e("[WXMetaModule] alert param parse error ", e);
-            }
-        }
-    }
-
-    @JSMethod(uiThread = true)
-    public void openLog(String open) {
-        Application application = WXEnvironment.getApplication();
-        if(application == null){
-            return;
-        }
-        ApplicationInfo info = application.getApplicationInfo();
-        if((info.flags & ApplicationInfo.FLAG_DEBUGGABLE)!= 0){
-            if(WXUtils.getBoolean(open, true)) {
-                WXEnvironment.setApkDebugable(true);
-                if(mWXSDKInstance != null) {
-                    Toast.makeText(mWXSDKInstance.getContext(), "log open success", Toast.LENGTH_SHORT).show();
-                }
-            }else{
-                WXEnvironment.setApkDebugable(false);
-                if(mWXSDKInstance != null) {
-                    Toast.makeText(mWXSDKInstance.getContext(), "log close success", Toast.LENGTH_SHORT).show();
-                }
-            }
-        }
-    }
-
-    @JSMethod(uiThread = false)
-    public void getPageInfo(JSCallback callback) {
-        if(callback == null){
-            return;
-        }
-        List<WXSDKInstance> instances = WXSDKManager.getInstance().getWXRenderManager().getAllInstances();
-        Map<String,Object> map = new HashMap<>(4);
-        for(WXSDKInstance instance : instances){
-            if(TextUtils.isEmpty(instance.getBundleUrl())){
-                continue;
-            }
-            map.put(instance.getBundleUrl(), instance.getTemplateInfo());
-        }
-        callback.invoke(map);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXModalUIModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXModalUIModule.java
deleted file mode 100644
index a158dcc..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXModalUIModule.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.text.TextUtils;
-import android.view.Gravity;
-import android.widget.EditText;
-import android.widget.Toast;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.utils.WXLogUtils;
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * WXModalUIModule module provide toast、alert、confirm、prompt to display the message.
- * for example(weex JS):
- * this.$call('modal','toast',{'message':'test toast','duration': 2.0});
- */
-public class WXModalUIModule extends WXSDKEngine.DestroyableModule {
-
-  public static final String OK = "OK";
-  public static final String CANCEL = "Cancel";
-  public static final String RESULT = "result";
-  public static final String DATA = "data";
-  public static final String MESSAGE = "message";
-  public static final String DURATION = "duration";
-  public static final String OK_TITLE = "okTitle";
-  public static final String CANCEL_TITLE = "cancelTitle";
-  public static final String DEFAULT = "default";
-  private Toast toast;
-  private Dialog activeDialog;
-
-  @SuppressLint("ShowToast")
-  @JSMethod(uiThread = true)
-  public void toast(JSONObject jsObj) {
-    if(mWXSDKInstance.getContext() == null){
-      return;
-    }
-    String message = "";
-    int duration = Toast.LENGTH_SHORT;
-    if (jsObj != null) {
-      try {
-        message = jsObj.getString(MESSAGE);
-        if(jsObj.containsKey(DURATION)) {
-          duration = jsObj.getInteger(DURATION);
-        }
-      } catch (Exception e) {
-        WXLogUtils.e("[WXModalUIModule] alert param parse error ", e);
-      }
-    }
-    if (TextUtils.isEmpty(message)) {
-      WXLogUtils.e("[WXModalUIModule] toast param parse is null ");
-      return;
-    }
-
-    if (duration > 3) {
-      duration = Toast.LENGTH_LONG;
-    } else {
-      duration = Toast.LENGTH_SHORT;
-    }
-    if (toast == null) {
-      toast = Toast.makeText(mWXSDKInstance.getContext(), message, duration);
-    } else {
-      toast.setDuration(duration);
-      toast.setText(message);
-    }
-    toast.setGravity(Gravity.CENTER, 0, 0);
-    toast.show();
-  }
-
-  @JSMethod(uiThread = true)
-  public void alert(JSONObject jsObj, final JSCallback callback) {
-
-    if (mWXSDKInstance.getContext() instanceof Activity) {
-
-      String message = "";
-      String okTitle = OK;
-      if (jsObj != null) {
-        try {
-          message = jsObj.getString(MESSAGE);
-          okTitle = jsObj.getString(OK_TITLE);
-        } catch (Exception e) {
-          WXLogUtils.e("[WXModalUIModule] alert param parse error ", e);
-        }
-      }
-      if (TextUtils.isEmpty(message)) {
-        message = "";
-      }
-      AlertDialog.Builder builder = new AlertDialog.Builder(mWXSDKInstance.getContext());
-      builder.setMessage(message);
-
-      final String okTitle_f = TextUtils.isEmpty(okTitle) ? OK : okTitle;
-      builder.setPositiveButton(okTitle_f, new OnClickListener() {
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-          if (callback != null) {
-            callback.invoke(okTitle_f);
-          }
-        }
-      });
-      AlertDialog alertDialog = builder.create();
-      alertDialog.setCanceledOnTouchOutside(false);
-      alertDialog.show();
-      tracking(alertDialog);
-    } else {
-      WXLogUtils.e("[WXModalUIModule] when call alert mWXSDKInstance.getContext() must instanceof Activity");
-    }
-  }
-
-  @JSMethod(uiThread = true)
-  public void confirm(JSONObject jsObj, final JSCallback callback) {
-
-    if (mWXSDKInstance.getContext() instanceof Activity) {
-      String message = "";
-      String okTitle = OK;
-      String cancelTitle = CANCEL;
-
-      if (jsObj != null) {
-        try {
-          message = jsObj.getString(MESSAGE);
-          okTitle = jsObj.getString(OK_TITLE);
-          cancelTitle = jsObj.getString(CANCEL_TITLE);
-        } catch (Exception e) {
-          WXLogUtils.e("[WXModalUIModule] confirm param parse error ", e);
-        }
-      }
-      if (TextUtils.isEmpty(message)) {
-        message = "";
-      }
-      AlertDialog.Builder builder = new AlertDialog.Builder(mWXSDKInstance.getContext());
-      builder.setMessage(message);
-
-      final String okTitleFinal = TextUtils.isEmpty(okTitle) ? OK : okTitle;
-      final String cancelTitleFinal = TextUtils.isEmpty(cancelTitle) ? CANCEL : cancelTitle;
-
-      builder.setPositiveButton(okTitleFinal, new OnClickListener() {
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-          if (callback != null) {
-            callback.invoke(okTitleFinal);
-          }
-        }
-      });
-      builder.setNegativeButton(cancelTitleFinal, new OnClickListener() {
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-          if (callback != null) {
-            callback.invoke(cancelTitleFinal);
-          }
-        }
-      });
-      AlertDialog alertDialog = builder.create();
-      alertDialog.setCanceledOnTouchOutside(false);
-      alertDialog.show();
-      tracking(alertDialog);
-    } else {
-      WXLogUtils.e("[WXModalUIModule] when call confirm mWXSDKInstance.getContext() must instanceof Activity");
-    }
-  }
-
-  @JSMethod(uiThread = true)
-  public void prompt(JSONObject jsObj, final JSCallback callback) {
-    if (mWXSDKInstance.getContext() instanceof Activity) {
-      String message = "";
-      String defaultValue = "";
-      String okTitle = OK;
-      String cancelTitle = CANCEL;
-
-      if (jsObj != null) {
-        try {
-          message = jsObj.getString(MESSAGE);
-          okTitle = jsObj.getString(OK_TITLE);
-          cancelTitle = jsObj.getString(CANCEL_TITLE);
-          defaultValue = jsObj.getString(DEFAULT);
-        } catch (Exception e) {
-          WXLogUtils.e("[WXModalUIModule] confirm param parse error ", e);
-        }
-      }
-
-      if (TextUtils.isEmpty(message)) {
-        message = "";
-      }
-      AlertDialog.Builder builder = new AlertDialog.Builder(mWXSDKInstance.getContext());
-      builder.setMessage(message);
-
-      final EditText editText = new EditText(mWXSDKInstance.getContext());
-      editText.setText(defaultValue);
-      builder.setView(editText);
-      final String okTitleFinal = TextUtils.isEmpty(okTitle) ? OK : okTitle;
-      final String cancelTitleFinal = TextUtils.isEmpty(cancelTitle) ? CANCEL : cancelTitle;
-      builder.setPositiveButton(okTitleFinal, new OnClickListener() {
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-          if (callback != null) {
-            Map<String, Object> result = new HashMap<String, Object>();
-            result.put(RESULT, okTitleFinal);
-            result.put(DATA, editText.getText().toString());
-            callback.invoke(result);
-          }
-        }
-      }).setNegativeButton(cancelTitleFinal, new OnClickListener() {
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-          if (callback != null) {
-            Map<String, Object> result = new HashMap<String, Object>();
-            result.put(RESULT, cancelTitleFinal);
-            result.put(DATA, editText.getText().toString());
-            callback.invoke(result);
-          }
-
-        }
-      });
-      AlertDialog alertDialog = builder.create();
-      alertDialog.setCanceledOnTouchOutside(false);
-      alertDialog.show();
-      tracking(alertDialog);
-    } else {
-      WXLogUtils.e("when call prompt mWXSDKInstance.getContext() must instanceof Activity");
-    }
-  }
-
-  private void tracking(Dialog dialog) {
-    activeDialog = dialog;
-    dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
-      @Override
-      public void onDismiss(DialogInterface dialog) {
-        activeDialog = null;
-      }
-    });
-  }
-
-  @Override
-  public void destroy() {
-    if (activeDialog != null && activeDialog.isShowing()) {
-      activeDialog.dismiss();
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXTimerModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXTimerModule.java
deleted file mode 100644
index aacd25a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXTimerModule.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import static com.taobao.weex.bridge.WXBridgeManager.KEY_ARGS;
-import static com.taobao.weex.bridge.WXBridgeManager.KEY_METHOD;
-import static com.taobao.weex.bridge.WXBridgeManager.METHOD_CALLBACK;
-import static com.taobao.weex.bridge.WXBridgeManager.METHOD_CALL_JS;
-import static com.taobao.weex.common.WXJSBridgeMsgType.MODULE_INTERVAL;
-import static com.taobao.weex.common.WXJSBridgeMsgType.MODULE_TIMEOUT;
-
-import android.annotation.SuppressLint;
-import android.os.Handler;
-import android.os.Message;
-import android.support.annotation.FloatRange;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.VisibleForTesting;
-import android.util.SparseArray;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.bridge.WXHashMap;
-import com.taobao.weex.bridge.WXJSObject;
-import com.taobao.weex.common.Destroyable;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.utils.WXJsonUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.HashMap;
-import com.taobao.weex.utils.WXUtils;
-
-public class WXTimerModule extends WXModule implements Destroyable, Handler.Callback {
-
-  @IntDef({MODULE_TIMEOUT, MODULE_INTERVAL})
-  @Retention(RetentionPolicy.SOURCE)
-  @interface MessageType {}
-
-  private final static String TAG = "timer";
-  private Handler handler;
-  private SparseArray<Integer> antiIntAutoBoxing;
-
-  @SuppressLint("UseSparseArrays")
-  public WXTimerModule() {
-    handler = new Handler(WXBridgeManager.getInstance().getJSLooper(), this);
-    antiIntAutoBoxing = new SparseArray<>();
-  }
-
-
-  @JSMethod(uiThread = false)
-  public void setTimeout(@IntRange(from = 1) int funcId, @FloatRange(from = 0) float delay) {
-    if(mWXSDKInstance != null) {
-      postOrHoldMessage(MODULE_TIMEOUT, funcId, (int) delay, WXUtils.parseInt(mWXSDKInstance.getInstanceId()));
-      if (null != mWXSDKInstance.getWXPerformance()){
-        mWXSDKInstance.getWXPerformance().timerInvokeCount++;
-      }
-      mWXSDKInstance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_TIMER_NUM,1);
-    }
-  }
-
-  @JSMethod(uiThread = false)
-  public void setInterval(@IntRange(from = 1) int funcId, @FloatRange(from = 0) float interval) {
-    if(mWXSDKInstance != null) {
-      postOrHoldMessage(MODULE_INTERVAL, funcId, (int) interval, WXUtils.parseInt(mWXSDKInstance.getInstanceId()));
-      if (null != mWXSDKInstance.getWXPerformance()){
-        mWXSDKInstance.getWXPerformance().timerInvokeCount++;
-      }
-      mWXSDKInstance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_TIMER_NUM,1);
-    }
-  }
-
-  @JSMethod(uiThread = false)
-  public void clearTimeout(@IntRange(from = 1) int funcId) {
-    if (funcId <= 0) {
-      return;
-    }
-    removeOrHoldMessage(MODULE_TIMEOUT, funcId);
-  }
-
-  @JSMethod(uiThread = false)
-  public void clearInterval(@IntRange(from = 1) int funcId) {
-    if (funcId <= 0) {
-      return;
-    }
-    removeOrHoldMessage(MODULE_INTERVAL, funcId);
-  }
-
-  @Override
-  public void destroy() {
-    if (handler != null) {
-      if(WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d(TAG, "Timer Module removeAllMessages: ");
-      }
-      handler.removeCallbacksAndMessages(null);
-      antiIntAutoBoxing.clear();
-    }
-  }
-
-  @Override
-  public boolean handleMessage(Message msg) {
-    boolean ret = false;
-    WXJSObject[] args;
-    if (msg != null) {
-      int what = msg.what;
-      if(WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d(TAG, "Timer Module handleMessage : " + msg.what);
-      }
-      switch (what) {
-        case MODULE_TIMEOUT:
-          if (msg.obj == null) {
-            break;
-          }
-          checkIfTimerInBack(msg.arg1);
-          args = createTimerArgs(msg.arg1, (Integer) msg.obj, false);
-          WXBridgeManager.getInstance().invokeExecJS(String.valueOf(msg.arg1), null, METHOD_CALL_JS, args, true);
-          ret = true;
-          break;
-        case MODULE_INTERVAL:
-          if (msg.obj == null) {
-            break;
-          }
-          checkIfTimerInBack(msg.arg1);
-          postMessage(MODULE_INTERVAL, (Integer) msg.obj, msg.arg2, msg.arg1);
-          args = createTimerArgs(msg.arg1, (Integer) msg.obj, true);
-          WXBridgeManager.getInstance().invokeExecJS(String.valueOf(msg.arg1), null, METHOD_CALL_JS, args, true);
-          ret = true;
-          break;
-        default:
-          break;
-      }
-    }
-    return ret;
-  }
-
-  private void checkIfTimerInBack(int instanceId){
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(String.valueOf(instanceId));
-    if (null == instance){
-      return;
-    }
-    if (instance.isViewDisAppear()){
-      instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_TIMER_BACK_NUM,1);
-    }
-  }
-
-  @VisibleForTesting
-  void setHandler(Handler handler) {
-    this.handler = handler;
-  }
-
-  private WXJSObject[] createTimerArgs(int instanceId, int funcId, boolean keepAlive) {
-    ArrayList<Object> argsList = new ArrayList<>();
-    argsList.add(funcId);
-    argsList.add(new HashMap<>());
-    argsList.add(keepAlive);
-    WXHashMap<String, Object> task = new WXHashMap<>();
-    task.put(KEY_METHOD, METHOD_CALLBACK);
-    task.put(KEY_ARGS, argsList);
-    Object[] tasks = {task};
-    return new WXJSObject[]{
-            new WXJSObject(WXJSObject.String, String.valueOf(instanceId)),
-            new WXJSObject(WXJSObject.JSON,
-                    WXJsonUtils.fromObjectToJSONString(tasks))};
-  }
-
-  private void postOrHoldMessage(@MessageType final int what,final int funcId,final int interval,final int instanceId) {
-    if(mWXSDKInstance.isPreRenderMode()) {
-      postMessage(what,funcId,interval,instanceId);
-    } else {
-      postMessage(what,funcId,interval,instanceId);
-    }
-  }
-
-  private void removeOrHoldMessage(@MessageType final int what,final int funcId) {
-    if(mWXSDKInstance.isPreRenderMode()) {
-      handler.removeMessages(what, antiIntAutoBoxing.get(funcId, funcId));
-    } else {
-      handler.removeMessages(what, antiIntAutoBoxing.get(funcId, funcId));
-    }
-  }
-
-  private void postMessage(@MessageType int what,
-                           @IntRange(from = 1) int funcId,
-                           @IntRange(from = 0) int interval, int instanceId) {
-    if (interval < 0 || funcId <= 0) {
-      WXLogUtils.e(TAG, "interval < 0 or funcId <=0");
-    } else {
-      if(antiIntAutoBoxing.get(funcId) == null) {
-        antiIntAutoBoxing.put(funcId, funcId);
-      }
-      Message message = handler
-              .obtainMessage(what, instanceId, interval, antiIntAutoBoxing.get(funcId));
-      handler.sendMessageDelayed(message, interval);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java
deleted file mode 100644
index 9878c85..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXWebViewModule.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.common.WXModule;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXWeb;
-
-public class WXWebViewModule extends WXModule{
-
-    private enum Action {
-        reload,
-        goBack,
-        goForward,
-        postMessage
-    }
-
-    @JSMethod(uiThread = true)
-    public void goBack(String ref) {
-        action(Action.goBack, ref);
-    }
-
-    @JSMethod(uiThread = true)
-    public void goForward(String ref) {
-        action(Action.goForward, ref);
-    }
-
-    @JSMethod(uiThread = true)
-    public void reload(String ref) {
-        action(Action.reload, ref);
-    }
-
-    @JSMethod(uiThread = true)
-    public void postMessage(String ref, Object msg) {
-        action(Action.postMessage, ref, msg);
-    }
-
-    private void action(Action action, String ref, Object data) {
-        WXComponent webComponent =
-            WXSDKManager.getInstance()
-                .getWXRenderManager()
-                .getWXComponent(mWXSDKInstance.getInstanceId(), ref);
-        if(webComponent instanceof WXWeb) {
-            ((WXWeb) webComponent).setAction(action.name(), data);
-        }
-    }
-
-    private void action(Action action, String ref) {
-        action(action, ref, null);
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/BaseFrameLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/BaseFrameLayout.java
deleted file mode 100644
index e12d52e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/BaseFrameLayout.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.widget.FrameLayout;
-import com.taobao.weex.ui.flat.widget.Widget;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import java.util.List;
-
-public class BaseFrameLayout extends FrameLayout{
-    private List<Widget> mWidgets;
-
-    public BaseFrameLayout(Context context){
-        super(context);
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        try {
-            dispatchDrawInterval(canvas);
-        } catch (Throwable e) {
-            WXLogUtils.e(WXLogUtils.getStackTrace(e));
-        }
-    }
-
-    protected void dispatchDrawInterval(Canvas canvas) {
-        if (mWidgets != null) {
-            canvas.save();
-            canvas.translate(getPaddingLeft(), getPaddingTop());
-            for (Widget widget : mWidgets) {
-                widget.draw(canvas);
-            }
-            canvas.restore();
-        } else {
-            WXViewUtils.clipCanvasWithinBorderBox(this, canvas);
-            super.dispatchDraw(canvas);
-        }
-    }
-    public void mountFlatGUI(List<Widget> widgets){
-        this.mWidgets = widgets;
-        if (mWidgets != null) {
-            setWillNotDraw(true);
-        }
-        invalidate();
-    }
-
-    public void unmountFlatGUI(){
-        mWidgets = null;
-        setWillNotDraw(false);
-        invalidate();
-    }
-
-    @Override
-    protected boolean verifyDrawable(@NonNull Drawable who) {
-        return mWidgets != null || super.verifyDrawable(who);
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/IRenderResult.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/IRenderResult.java
deleted file mode 100644
index dab1106..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/IRenderResult.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-
-import com.taobao.weex.ui.component.WXComponent;
-
-public interface IRenderResult<T extends WXComponent> {
-    T getComponent();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/IRenderStatus.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/IRenderStatus.java
deleted file mode 100644
index f61b0fa..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/IRenderStatus.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-
-import com.taobao.weex.ui.component.WXComponent;
-
-public interface IRenderStatus<T extends WXComponent> {
-
-  public void holdComponent(T component);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWXScroller.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/IWXScroller.java
deleted file mode 100644
index 942c7aa..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWXScroller.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-public interface IWXScroller {
-
-  void destroy();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWXTextView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/IWXTextView.java
deleted file mode 100644
index 60b2533..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWXTextView.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-public interface IWXTextView {
-
-  CharSequence getText();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java
deleted file mode 100644
index b3bc8e7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/IWebView.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.view.View;
-
-import java.util.Map;
-
-public interface IWebView {
-    public View getView();
-    public void destroy();
-    public void loadUrl(String url);
-    public void loadDataWithBaseURL(String source);
-    public void reload();
-    public void goBack();
-    public void goForward();
-    public void postMessage(Object msg);
-    public void setShowLoading(boolean shown);
-    public void setOnErrorListener(OnErrorListener listener);
-    public void setOnPageListener(OnPageListener listener);
-    public void setOnMessageListener(OnMessageListener listener);
-
-    public interface OnErrorListener {
-        public void onError(String type, Object message);
-    }
-
-    public interface OnPageListener {
-        public void onReceivedTitle(String title);
-        public void onPageStart(String url);
-        public void onPageFinish(String url, boolean canGoBack, boolean canGoForward);
-    }
-
-    public interface OnMessageListener {
-        public void onMessage(Map<String, Object> params);
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXBaseCircleIndicator.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXBaseCircleIndicator.java
deleted file mode 100644
index 43264bd..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXBaseCircleIndicator.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.support.v4.view.ViewPager;
-import android.support.v4.view.ViewPager.OnPageChangeListener;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.utils.WXViewUtils;
-
-
-public class WXBaseCircleIndicator extends FrameLayout implements WXGestureObservable {
-
-  private final Paint mPaintPage = new Paint();
-  private final Paint mPaintFill = new Paint();
-  private WXGesture wxGesture;
-  private WXCircleViewPager mCircleViewPager;
-
-  /**
-   * Radius of the circle
-   */
-  private float radius;
-  /**
-   * Padding of the circle
-   */
-  private float circlePadding;
-  /**
-   * Fill color of unselected circle
-   */
-  private int pageColor = Color.LTGRAY;
-  /**
-   * Fill color of the selected circle
-   */
-  private int fillColor = Color.DKGRAY;
-  private int realCurrentItem;
-
-  private OnPageChangeListener mListener;
-
-
-  public WXBaseCircleIndicator(Context context) {
-    super(context);
-    init();
-  }
-
-  private void init() {
-    radius = WXViewUtils.dip2px(5);
-    circlePadding = WXViewUtils.dip2px(5);
-    pageColor = Color.LTGRAY;
-    fillColor = Color.DKGRAY;
-
-    mPaintFill.setStyle(Style.FILL);
-    mPaintFill.setAntiAlias(true);
-    mPaintPage.setAntiAlias(true);
-    mPaintPage.setColor(pageColor);
-    mPaintFill.setStyle(Style.FILL);
-    mPaintFill.setColor(fillColor);
-    this.setWillNotDraw(false);
-
-  }
-
-  /**
-   * @param context
-   * @param attrs
-   */
-  public WXBaseCircleIndicator(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    init();
-  }
-
-  /**
-   * @param viewPager the mCircleViewPager to set
-   */
-  public void setCircleViewPager(WXCircleViewPager viewPager) {
-    mCircleViewPager = viewPager;
-    if (mCircleViewPager != null) {
-      if (mListener == null) {
-        mListener = new ViewPager.SimpleOnPageChangeListener() {
-          @Override
-          public void onPageSelected(int position) {
-            realCurrentItem = mCircleViewPager.getRealCurrentItem();
-            invalidate();
-          }
-        };
-      }
-      this.mCircleViewPager.addOnPageChangeListener(mListener);
-      this.realCurrentItem = mCircleViewPager.getRealCurrentItem();
-      if (realCurrentItem < 0) {
-        realCurrentItem = 0;
-      }
-    }
-    requestLayout();
-  }
-
-  /**
-   * @param radius the radius to set
-   */
-  public void setRadius(float radius) {
-    this.radius = radius;
-  }
-
-  /**
-   * @param fillColor the fillColor to set
-   */
-  public void setFillColor(int fillColor) {
-    this.fillColor = fillColor;
-    mPaintFill.setColor(fillColor);
-  }
-
-  public void setPageColor(int pageColor) {
-    this.pageColor = pageColor;
-    mPaintPage.setColor(pageColor);
-  }
-
-  /**
-   * @return the realCurrentItem
-   */
-  public int getRealCurrentItem() {
-    return realCurrentItem;
-  }
-
-  /**
-   * @param realCurrentItem the realCurrentItem to set
-   */
-  public void setRealCurrentItem(int realCurrentItem) {
-    this.realCurrentItem = realCurrentItem;
-    invalidate();
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  @Override
-  public boolean dispatchTouchEvent(MotionEvent event) {
-    boolean result = super.dispatchTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-    return result;
-  }
-
-  @Override
-  protected void onDraw(Canvas canvas) {
-    super.onDraw(canvas);
-
-    float dotWidth = (circlePadding + radius) * 2;
-
-    float firstCenterX = getWidth() / 2 - (dotWidth * (getCount() - 1) / 2);
-    float firstCenterY = getHeight() / 2 + getPaddingTop();
-
-    for (int i = 0; i < getCount(); i++) {
-      float dx = firstCenterX + dotWidth * i;
-      float dy = firstCenterY;
-      if (i != realCurrentItem) {
-        canvas.drawCircle(dx, dy, radius, mPaintPage);
-      } else {
-        canvas.drawCircle(dx, dy, radius, mPaintFill);
-      }
-    }
-  }
-
-  @Override
-  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
-    int viewWidth;
-    int viewHeight;
-
-    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
-    if (widthMode == MeasureSpec.EXACTLY) {
-      viewWidth = widthSize;
-    } else {
-      viewWidth = (int) (getPaddingLeft() + radius * 2 * getCount() + circlePadding * (getCount() - 1) + getPaddingRight()) + 1;
-    }
-
-    if (heightMode == MeasureSpec.EXACTLY) {
-      viewHeight = heightSize;
-    } else {
-      viewHeight = (int) (getPaddingTop() + radius * 2 + getPaddingBottom()) + 1;
-    }
-    setMeasuredDimension(viewWidth, viewHeight);
-  }
-
-  /**
-   * @return the count
-   */
-  public int getCount() {
-    if (mCircleViewPager == null || mCircleViewPager.getAdapter() == null) {
-      return 0;
-    }
-    return mCircleViewPager.getRealCount();
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXBaseRefreshLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXBaseRefreshLayout.java
deleted file mode 100644
index ff45491..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXBaseRefreshLayout.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.content.Context;
-
-public class WXBaseRefreshLayout extends WXFrameLayout {
-
-  public WXBaseRefreshLayout(Context context) {
-    super(context);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleIndicator.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleIndicator.java
deleted file mode 100644
index b3acdb7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleIndicator.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.content.Context;
-
-public class WXCircleIndicator extends WXBaseCircleIndicator {
-
-  public WXCircleIndicator(Context context) {
-    super(context);
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCirclePageAdapter.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCirclePageAdapter.java
deleted file mode 100644
index 1b5b219..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCirclePageAdapter.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.support.v4.view.PagerAdapter;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class WXCirclePageAdapter extends PagerAdapter {
-
-  /**
-   * Subviews
-   */
-  private List<View> views = new ArrayList<>();
-  private List<View> shadow = new ArrayList<>();
-  private boolean needLoop = true;
-
-  public boolean isRTL = false;
-  private List<View> originalViews = new ArrayList<>();
-
-  public WXCirclePageAdapter(List<View> views, boolean needLoop) {
-    super();
-    this.views = new ArrayList<>(views);
-    this.originalViews = new ArrayList<>(views);
-    this.needLoop = needLoop;
-  }
-
-  public void setLayoutDirectionRTL(boolean isRTL) {
-    if (isRTL == this.isRTL) return;
-    this.isRTL = isRTL;
-    this.views = new ArrayList<>(this.originalViews);
-    if (isRTL) {
-      Collections.reverse(this.views);
-    }
-    ensureShadow();
-  }
-
-  public WXCirclePageAdapter() {
-    this(true);
-  }
-
-  public WXCirclePageAdapter(boolean needLoop) {
-    super();
-    this.needLoop = needLoop;
-  }
-
-  public void addPageView(View view) {
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("onPageSelected >>>> addPageView");
-    }
-
-    originalViews.add(view);
-    if (this.isRTL) {
-      views.add(0, view);
-    } else {
-      views.add(view);
-    }
-    ensureShadow();
-  }
-
-  public void removePageView(View view) {
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("onPageSelected >>>> removePageView");
-    }
-    views.remove(view);
-    originalViews.remove(view);
-    ensureShadow();
-  }
-
-  public void replacePageView(View oldView, View newView) {
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("onPageSelected >>>> replacePageView");
-    }
-
-    int index = views.indexOf(oldView);
-    views.remove(index);
-    views.add(index, newView);
-    ensureShadow();
-
-    index = originalViews.indexOf(oldView);
-    originalViews.remove(index);
-    originalViews.add(index, newView);
-  }
-
-  @Override
-  public int getCount() {
-    return shadow.size();
-  }
-
-  public int getRealCount() {
-    return views.size();
-  }
-
-  @Override
-  public Object instantiateItem(ViewGroup container, int position) {
-    View pageView = null;
-    try {
-      pageView = shadow.get(position);
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.d("onPageSelected >>>> instantiateItem >>>>> position:" + position + ",position % getRealCount()" + position % getRealCount());
-      }
-      if (pageView.getParent() == null) {
-        container.addView(pageView);
-      } else {
-        ((ViewGroup) pageView.getParent()).removeView(pageView);
-        container.addView(pageView);
-      }
-    } catch (Exception e) {
-      WXLogUtils.e("[CirclePageAdapter] instantiateItem: ", e);
-    }
-    return pageView;
-  }
-
-  @Override
-  public void destroyItem(ViewGroup container, int position, Object object) {
-    if (WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("onPageSelected >>>> destroyItem >>>>> position:" + position);
-    }
-    // container.removeView((View) object);
-  }
-
-  @Override
-  public boolean isViewFromObject(View view, Object object) {
-    return view == object;
-  }
-
-  @Override
-  public int getItemPosition(Object object) {
-    return POSITION_NONE;
-  }
-
-  public int getPagePosition(View page) {
-    return views.indexOf(page);
-  }
-
-  public int getItemIndex(Object object) {
-    if (object instanceof View) {
-      return views.indexOf(object);
-    } else {
-      return -1;
-    }
-  }
-
-  public List<View> getViews(){
-    return views;
-  }
-
-  private void ensureShadow() {
-    List<View> temp = new ArrayList<>();
-    if (needLoop && views.size() > 2) {
-      temp.add(0, views.get(views.size() - 1));
-      for (View view : views) {
-        temp.add(view);
-      }
-      temp.add(views.get(0));
-    } else {
-      temp.addAll(views);
-    }
-    shadow.clear();
-    notifyDataSetChanged();
-    shadow.addAll(temp);
-    notifyDataSetChanged();
-  }
-
-  public int getRealPosition(int shadowPosition) {
-    if (shadowPosition < 0 || shadowPosition >= shadow.size()) {
-      return -1;
-    } else {
-      return getItemIndex(shadow.get(shadowPosition));
-    }
-  }
-
-  public int getFirst() {
-    if (needLoop && views.size() > 2) {
-      return 1;
-    } else {
-      return 0;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleViewPager.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleViewPager.java
deleted file mode 100644
index fc48fe4..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleViewPager.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.reflect.Field;
-
-/**
- */
-@SuppressLint("HandlerLeak")
-public class WXCircleViewPager extends ViewPager implements WXGestureObservable {
-
-  private final int SCROLL_TO_NEXT = 1;
-  private WXGesture wxGesture;
-  private boolean isAutoScroll;
-  private long intervalTime = 3 * 1000;
-  private WXSmoothScroller mScroller;
-  private boolean needLoop = true;
-  private boolean scrollable = true;
-  private int mState = ViewPager.SCROLL_STATE_IDLE;
-  private Handler mAutoScrollHandler = new Handler(Looper.getMainLooper()) {
-    @Override
-    public void handleMessage(Message msg) {
-      if (msg.what == SCROLL_TO_NEXT) {
-        WXLogUtils.d("[CircleViewPager] trigger auto play action");
-        showNextItem();
-        this.sendEmptyMessageDelayed(SCROLL_TO_NEXT, intervalTime);
-        return;
-      }
-      super.handleMessage(msg);
-    }
-  };
-
-  @SuppressLint("NewApi")
-  public WXCircleViewPager(Context context) {
-    super(context);
-    init();
-  }
-
-  private void init() {
-    setOverScrollMode(View.OVER_SCROLL_NEVER);
-
-    addOnPageChangeListener(new OnPageChangeListener() {
-      @Override
-      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-
-      }
-
-      @Override
-      public void onPageSelected(int position) {
-
-      }
-
-      @Override
-      public void onPageScrollStateChanged(int state) {
-        mState = state;
-        WXCirclePageAdapter adapter = getCirclePageAdapter();
-        int currentItemInternal = WXCircleViewPager.super.getCurrentItem();
-        if (needLoop && state == ViewPager.SCROLL_STATE_IDLE && adapter.getCount() > 1) {
-          if (currentItemInternal == adapter.getCount() - 1) {
-            superSetCurrentItem(1, false);
-          } else if (currentItemInternal == 0) {
-            superSetCurrentItem(adapter.getCount() - 2, false);
-          }
-        }
-      }
-    });
-
-    postInitViewPager();
-  }
-
-  /**
-   * Override the Scroller instance with our own class so we can change the
-   * duration
-   */
-  private void postInitViewPager() {
-    if (isInEditMode()) {
-      return;
-    }
-    try {
-      Field scroller = ViewPager.class.getDeclaredField("mScroller");
-      scroller.setAccessible(true);
-      Field interpolator = ViewPager.class
-              .getDeclaredField("sInterpolator");
-      interpolator.setAccessible(true);
-
-      mScroller = new WXSmoothScroller(getContext(),
-              (Interpolator) interpolator.get(null));
-      scroller.set(this, mScroller);
-    } catch (Exception e) {
-      WXLogUtils.e("[CircleViewPager] postInitViewPager: ", e);
-    }
-  }
-
-  @SuppressLint("NewApi")
-  public WXCircleViewPager(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    init();
-  }
-
-  @Override
-  public int getCurrentItem() {
-    return getRealCurrentItem();
-  }
-
-  public int superGetCurrentItem() {
-    return super.getCurrentItem();
-  }
-
-  @Override
-  public boolean onInterceptTouchEvent(MotionEvent ev) {
-    try {
-      return scrollable && super.onInterceptTouchEvent(ev);
-    } catch (IllegalArgumentException e) {
-      e.printStackTrace();
-    } catch (ArrayIndexOutOfBoundsException e) {
-      e.printStackTrace();
-    }
-    return false;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent ev) {
-    if(!scrollable) {
-      return true;
-    }
-    return super.onTouchEvent(ev);
-  }
-
-  @Override
-  public void scrollTo(int x, int y) {
-    if(scrollable || mState != ViewPager.SCROLL_STATE_DRAGGING) {
-      super.scrollTo(x, y);
-    }
-  }
-
-  /**
-   * Start auto scroll. Must be called after {@link #setAdapter(PagerAdapter)}
-   */
-  public void startAutoScroll() {
-    isAutoScroll = true;
-    mAutoScrollHandler.removeCallbacksAndMessages(null);
-    mAutoScrollHandler.sendEmptyMessageDelayed(SCROLL_TO_NEXT, intervalTime);
-  }
-
-  public void pauseAutoScroll(){
-    mAutoScrollHandler.removeCallbacksAndMessages(null);
-  }
-
-  /**
-   * Stop auto scroll.
-   */
-  public void stopAutoScroll() {
-    isAutoScroll = false;
-    mAutoScrollHandler.removeCallbacksAndMessages(null);
-  }
-
-  public boolean isAutoScroll() {
-    return isAutoScroll;
-  }
-
-  @Override
-  public void setCurrentItem(int item) {
-    setRealCurrentItem(item);
-  }
-
-  /**
-   * @return the circlePageAdapter
-   */
-  public WXCirclePageAdapter getCirclePageAdapter() {
-    return (WXCirclePageAdapter) getAdapter();
-  }
-
-  /**
-   * @param circlePageAdapter the circlePageAdapter to set
-   */
-  public void setCirclePageAdapter(WXCirclePageAdapter circlePageAdapter) {
-    this.setAdapter(circlePageAdapter);
-  }
-
-  /**
-   * Get auto scroll interval. The time unit is micro second.
-   * The default time interval is 3000 micro second
-   * @return the intervalTime
-   */
-  public long getIntervalTime() {
-    return intervalTime;
-  }
-
-  /**
-   * Set auto scroll interval. The time unit is micro second.
-   * The default time interval is 3000 micro second
-   * @param intervalTime the intervalTime to set
-   */
-  public void setIntervalTime(long intervalTime) {
-    this.intervalTime = intervalTime;
-  }
-
-  public void setCircle(boolean circle) {
-    needLoop = circle;
-  }
-
-  @Override
-  public boolean dispatchTouchEvent(MotionEvent ev) {
-    switch (ev.getAction()) {
-      case MotionEvent.ACTION_DOWN:
-      case MotionEvent.ACTION_MOVE:
-        mAutoScrollHandler.removeCallbacksAndMessages(null);
-        break;
-      case MotionEvent.ACTION_UP:
-      case MotionEvent.ACTION_CANCEL:
-        if (isAutoScroll()) {
-          mAutoScrollHandler.sendEmptyMessageDelayed(SCROLL_TO_NEXT, intervalTime);
-        }
-        break;
-    }
-    try{
-      boolean result = super.dispatchTouchEvent(ev);
-      if (wxGesture != null) {
-        result |= wxGesture.onTouch(this, ev);
-      }
-      return result;
-    }catch (Exception e){
-      return  false;
-    }
-  }
-
-  public void destory() {
-    mAutoScrollHandler.removeCallbacksAndMessages(null);
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  public int getRealCurrentItem() {
-    int i = super.getCurrentItem();
-    return ((WXCirclePageAdapter) getAdapter()).getRealPosition(i);
-  }
-
-  private void setRealCurrentItem(int item) {
-    superSetCurrentItem(((WXCirclePageAdapter) getAdapter()).getFirst() + item, false);
-  }
-
-  private void superSetCurrentItem(int item, boolean smooth) {
-    try {
-      super.setCurrentItem(item, smooth);
-    } catch (IllegalStateException e) {
-      WXLogUtils.e(e.toString());
-      if (getAdapter() != null) {
-        getAdapter().notifyDataSetChanged();
-        super.setCurrentItem(item, smooth);
-      }
-    }
-  }
-
-  public int getRealCount() {
-    return ((WXCirclePageAdapter) getAdapter()).getRealCount();
-  }
-
-  @Override
-  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-    try {
-      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    } catch (IllegalStateException e) {
-      WXLogUtils.e(e.toString());
-      if (getAdapter() != null) {
-        getAdapter().notifyDataSetChanged();
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-      }
-    }
-  }
-
-  public boolean isScrollable() {
-    return scrollable;
-  }
-
-  public void setScrollable(boolean scrollable) {
-    this.scrollable = scrollable;
-  }
-
-  private void showNextItem() {
-    if (this.getCirclePageAdapter() != null && this.getCirclePageAdapter().isRTL) {
-      if (!needLoop && superGetCurrentItem() == 0) {
-        return;
-      }
-      if (getRealCount() == 2 && superGetCurrentItem() == 0) {
-        superSetCurrentItem(1, true);
-      } else {
-        superSetCurrentItem(superGetCurrentItem() - 1, true);
-      }
-    } else {
-      if (!needLoop && superGetCurrentItem() == getRealCount() - 1) {
-        return;
-      }
-      if (getRealCount() == 2 && superGetCurrentItem() == 1) {
-        superSetCurrentItem(0, true);
-      } else {
-        superSetCurrentItem(superGetCurrentItem() + 1, true);
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXEditText.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXEditText.java
deleted file mode 100644
index 3607c41..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXEditText.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.os.Build;
-import android.view.ActionMode;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.ViewParent;
-import android.widget.EditText;
-
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-
-/**
- * Wrapper class for editText
- */
-@SuppressLint("AppCompatCustomView")
-public class WXEditText extends EditText implements WXGestureObservable {
-
-  private WXGesture wxGesture;
-  private int mLines = 1;
-  private boolean mAllowDisableMovement = true;
-  private boolean mAllowCopyPaste = true;
-
-  public WXEditText(Context context) {
-    super(context);
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-      setBackground(null);
-    } else {
-      setBackgroundDrawable(null);
-    }
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  @Override
-  public void setLines(int lines) {
-    super.setLines(lines);
-    mLines = lines;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    boolean result = super.onTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-
-    ViewParent parent = getParent();
-    if(parent != null){
-      switch (event.getAction() & MotionEvent.ACTION_MASK){
-        case MotionEvent.ACTION_DOWN:
-          if(mLines < getLineCount()) {
-            //scrollable
-            parent.requestDisallowInterceptTouchEvent(true);
-          }
-          break;
-        case MotionEvent.ACTION_UP:
-        case MotionEvent.ACTION_CANCEL:
-          parent.requestDisallowInterceptTouchEvent(false);
-          break;
-      }
-    }
-    return result;
-  }
-
-  @Override
-  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-    super.onSizeChanged(w, h, oldw, oldh);
-    if (getLayout() != null) {
-      int contentH = getLayout().getHeight();
-      //TODO: known issue,set movement to null will make cursor disappear.
-      if (mAllowDisableMovement && h < contentH) {
-        setMovementMethod(null);
-      } else {
-        setMovementMethod(getDefaultMovementMethod());
-      }
-    }
-  }
-
-  public void setAllowDisableMovement(boolean allow) {
-    mAllowDisableMovement = allow;
-  }
-
-  public void setAllowCopyPaste(boolean allow) {
-    mAllowCopyPaste = allow;
-    if (allow) {
-      setLongClickable(true);
-      setCustomSelectionActionModeCallback(null);
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-        setCustomInsertionActionModeCallback(null);
-      }
-    } else {
-      setLongClickable(false);
-      ActionMode.Callback callback = new ActionMode.Callback() {
-        @Override
-        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-          return false;
-        }
-
-        @Override
-        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-          return false;
-        }
-
-        @Override
-        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-          return false;
-        }
-
-        @Override
-        public void onDestroyActionMode(ActionMode mode) {
-
-        }
-      };
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-        setCustomInsertionActionModeCallback(callback);
-      }
-      setCustomSelectionActionModeCallback(callback);
-    }
-  }
-
-  @Override
-  public boolean onTextContextMenuItem(int id) {
-    return !mAllowCopyPaste || super.onTextContextMenuItem(id);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java
deleted file mode 100644
index 04b8257..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.support.annotation.Nullable;
-import android.view.MotionEvent;
-import android.view.View;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXDiv;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.utils.WXExceptionUtils;
-import com.taobao.weex.utils.WXLogUtils;
-import java.lang.ref.WeakReference;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * FrameLayout wrapper
- *
- */
-public class WXFrameLayout extends BaseFrameLayout implements WXGestureObservable,IRenderStatus<WXDiv>,IRenderResult<WXDiv>{
-
-  private WeakReference<WXDiv> mWeakReference;
-  private WXGesture wxGesture;
-
-
-  public WXFrameLayout(Context context) {
-    super(context);
-  }
-
-  @Nullable
-  @Override
-  public WXDiv getComponent() {
-    return null != mWeakReference ? mWeakReference.get() : null;
-  }
-
-  @Override
-  public void holdComponent(WXDiv component) {
-    mWeakReference = new WeakReference<WXDiv>(component);
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  @Override
-  public boolean dispatchTouchEvent(MotionEvent event) {
-    boolean result = super.dispatchTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-    return result;
-  }
-  @Override
-  protected void dispatchDraw(Canvas canvas) {
-    try {
-      super.dispatchDrawInterval(canvas);
-    } catch (Throwable e) {
-      if (getComponent() != null) {
-        notifyLayerOverFlow();
-        if (null != getComponent()){
-          WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(getComponent().getInstanceId());
-          if (null != instance && null != instance.getApmForInstance() &&!instance.getApmForInstance().hasReportLayerOverDraw){
-            instance.getApmForInstance().hasReportLayerOverDraw = true;
-            reportLayerOverFlowError();
-          }
-        }
-      }
-      WXLogUtils.e("Layer overflow limit error", WXLogUtils.getStackTrace(e));
-    }
-  }
-  private int reportLayerOverFlowError() {
-    int deep = calLayerDeep(this, 0);
-    if (getComponent() != null) {
-      WXExceptionUtils.commitCriticalExceptionRT(getComponent().getInstanceId(),
-              WXErrorCode.WX_RENDER_ERR_LAYER_OVERFLOW,
-              "draw android view",
-              WXErrorCode.WX_RENDER_ERR_LAYER_OVERFLOW.getErrorMsg() + "Layer overflow limit error: " + deep + " layers!",
-              null);
-    }
-    return deep;
-  }
-  private int calLayerDeep(View view, int deep) {
-    deep++;
-    if (view.getParent() != null && view.getParent() instanceof View) {
-      return calLayerDeep((View) view.getParent(), deep);
-    }
-    return deep;
-  }
-
-  public void notifyLayerOverFlow() {
-    if (getComponent() == null)
-      return;
-
-    WXSDKInstance instance = getComponent().getInstance();
-    if (instance == null)
-      return;
-
-    if (instance.getLayerOverFlowListeners() == null)
-      return;
-
-    for (String ref : instance.getLayerOverFlowListeners()) {
-      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instance.getInstanceId(), ref);
-      Map<String, Object> params = new HashMap<>();
-      params.put(Constants.Weex.REF, ref);
-      params.put(Constants.Weex.INSTANCEID, component.getInstanceId());
-      component.fireEvent(Constants.Event.LAYEROVERFLOW, params);
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXHorizontalScrollView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXHorizontalScrollView.java
deleted file mode 100644
index 8ae842d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXHorizontalScrollView.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.HorizontalScrollView;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public class WXHorizontalScrollView extends HorizontalScrollView implements IWXScroller, WXGestureObservable {
-
-  private WXGesture wxGesture;
-  private ScrollViewListener mScrollViewListener;
-  private List<ScrollViewListener> mScrollViewListeners;
-  private boolean scrollable = true;
-
-  public WXHorizontalScrollView(Context context) {
-    super(context);
-    init();
-  }
-
-  private void init() {
-    setWillNotDraw(false);
-    setOverScrollMode(View.OVER_SCROLL_NEVER);
-  }
-
-  public WXHorizontalScrollView(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    init();
-  }
-
-  @Override
-  protected void onScrollChanged(int l, int t, int oldl, int oldt) {
-    super.onScrollChanged(l, t, oldl, oldt);
-    if (mScrollViewListener != null) {
-      mScrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
-    }
-    if (mScrollViewListeners != null) {
-      for (ScrollViewListener listener : mScrollViewListeners) {
-        listener.onScrollChanged(this, l, t, oldl, oldt);
-      }
-    }
-  }
-
-  public void setScrollViewListener(ScrollViewListener scrollViewListener) {
-    this.mScrollViewListener = scrollViewListener;
-  }
-
-  @Override
-  public void destroy() {
-
-  }
-
-  public void addScrollViewListener(ScrollViewListener scrollViewListener) {
-    if (mScrollViewListeners == null) {
-      mScrollViewListeners = new CopyOnWriteArrayList<>();
-    }
-    if (!mScrollViewListeners.contains(scrollViewListener)) {
-      mScrollViewListeners.add(scrollViewListener);
-    }
-  }
-
-  public void removeScrollViewListener(ScrollViewListener scrollViewListener) {
-    mScrollViewListeners.remove(scrollViewListener);
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  @Override
-  public boolean dispatchTouchEvent(MotionEvent event) {
-    boolean result = super.dispatchTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-    return result;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent ev) {
-    if(!scrollable) {
-      return true; // when scrollable is set to false, then eat the touch event
-    }
-    return super.onTouchEvent(ev);
-  }
-
-  public interface ScrollViewListener {
-
-    void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy);
-  }
-
-  public boolean isScrollable() {
-    return scrollable;
-  }
-
-  public void setScrollable(boolean scrollable) {
-    this.scrollable = scrollable;
-  }
-
-  public Rect getContentFrame() {
-    return new Rect(0, 0, computeHorizontalScrollRange(), computeVerticalScrollRange());
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java
deleted file mode 100644
index 5ef242f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import com.taobao.weex.ui.component.WXImage;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.utils.ImageDrawable;
-import com.taobao.weex.utils.WXLogUtils;
-import java.lang.ref.WeakReference;
-import java.util.Arrays;
-
-@SuppressLint("AppCompatCustomView")
-public class WXImageView extends ImageView implements WXGestureObservable,
-        IRenderStatus<WXImage>,
-        IRenderResult<WXImage>, WXImage.Measurable {
-
-  private WeakReference<WXImage> mWeakReference;
-  private WXGesture wxGesture;
-  private float[] borderRadius;
-  private boolean gif;
-  private boolean isBitmapReleased = false;
-  private boolean enableBitmapAutoManage = true;
-
-
-  public WXImageView(Context context) {
-    super(context);
-  }
-
-  @Override
-  public void setImageResource(int resId) {
-    Drawable drawable = getResources().getDrawable(resId);
-    setImageDrawable(drawable);
-  }
-
-  public void setImageDrawable(@Nullable Drawable drawable, boolean isGif) {
-    this.gif = isGif;
-    ViewGroup.LayoutParams layoutParams;
-    if ((layoutParams = getLayoutParams()) != null) {
-      Drawable wrapDrawable = ImageDrawable.createImageDrawable(drawable,
-              getScaleType(), borderRadius,
-              layoutParams.width - getPaddingLeft() - getPaddingRight(),
-              layoutParams.height - getPaddingTop() - getPaddingBottom(),
-              isGif);
-      if (wrapDrawable instanceof ImageDrawable) {
-        ImageDrawable imageDrawable = (ImageDrawable) wrapDrawable;
-        if (!Arrays.equals(imageDrawable.getCornerRadii(), borderRadius)) {
-          imageDrawable.setCornerRadii(borderRadius);
-        }
-      }
-      super.setImageDrawable(wrapDrawable);
-      if (mWeakReference != null) {
-        WXImage component = mWeakReference.get();
-        if (component != null) {
-          component.readyToRender();
-        }
-      }
-    }
-  }
-
-  @Override
-  public void setImageDrawable(@Nullable Drawable drawable) {
-    setImageDrawable(drawable, gif);
-  }
-
-  @Override
-  public void setImageBitmap(@Nullable Bitmap bm) {
-    setImageDrawable(bm == null ? null : new BitmapDrawable(getResources(), bm));
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    boolean result = super.onTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-    return result;
-  }
-
-  public void setBorderRadius(@NonNull float[] borderRadius) {
-    this.borderRadius = borderRadius;
-  }
-
-  @Override
-  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-    super.onLayout(changed, left, top, right, bottom);
-    if (changed) {
-      setImageDrawable(getDrawable(), gif);
-    }
-  }
-
-  @Override
-  public void holdComponent(WXImage component) {
-    mWeakReference = new WeakReference<>(component);
-  }
-
-  @Nullable
-  @Override
-  public WXImage getComponent() {
-    return null != mWeakReference ? mWeakReference.get() : null;
-  }
-
-  @Override
-  public int getNaturalWidth() {
-    Drawable drawable = getDrawable();
-    if (drawable != null) {
-      if (drawable instanceof ImageDrawable) {
-        return ((ImageDrawable) drawable).getBitmapWidth();
-      } else if (drawable instanceof BitmapDrawable) {
-        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
-        if (bitmap != null) {
-          return bitmap.getWidth();
-        } else {
-          WXLogUtils.w("WXImageView", "Bitmap on " + drawable.toString() + " is null");
-        }
-      } else {
-        WXLogUtils.w("WXImageView", "Not supported drawable type: " + drawable.getClass().getSimpleName());
-      }
-    }
-    return -1;
-  }
-
-  @Override
-  public int getNaturalHeight() {
-    Drawable drawable = getDrawable();
-    if (drawable != null) {
-      if (drawable instanceof ImageDrawable) {
-        return ((ImageDrawable) drawable).getBitmapHeight();
-      } else if (drawable instanceof BitmapDrawable) {
-        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
-        if (bitmap != null) {
-          return bitmap.getHeight();
-        } else {
-          WXLogUtils.w("WXImageView", "Bitmap on " + drawable.toString() + " is null");
-        }
-      } else {
-        WXLogUtils.w("WXImageView", "Not supported drawable type: " + drawable.getClass().getSimpleName());
-      }
-    }
-    return -1;
-  }
-
-  private boolean mOutWindowVisibilityChangedReally;
-  @Override
-  public void dispatchWindowVisibilityChanged(int visibility) {
-    mOutWindowVisibilityChangedReally = true;
-    super.dispatchWindowVisibilityChanged(visibility);
-    mOutWindowVisibilityChangedReally = false;
-  }
-
-  @Override
-  protected void onWindowVisibilityChanged(int visibility) {
-    super.onWindowVisibilityChanged(visibility);
-    if(mOutWindowVisibilityChangedReally){
-      if(visibility == View.VISIBLE){
-        autoRecoverImage();
-      }else{
-        autoReleaseImage();
-      }
-    }
-  }
-
-
-  @Override
-  protected void onAttachedToWindow() {
-    super.onAttachedToWindow();
-    autoRecoverImage();
-  }
-
-  @Override
-  protected void onDetachedFromWindow() {
-    super.onDetachedFromWindow();
-    autoReleaseImage();
-
-  }
-
-
-  @Override
-  public void onStartTemporaryDetach () {
-    super.onStartTemporaryDetach();
-    autoReleaseImage();
-
-  }
-
-
-  @Override
-  public void onFinishTemporaryDetach () {
-    super.onFinishTemporaryDetach();
-    autoRecoverImage();
-  }
-
-
-  public void setEnableBitmapAutoManage(boolean enableBitmapAutoManage) {
-    this.enableBitmapAutoManage = enableBitmapAutoManage;
-  }
-
-  public void autoReleaseImage(){
-    if(enableBitmapAutoManage) {
-      if (!isBitmapReleased) {
-        isBitmapReleased = true;
-        WXImage image = getComponent();
-        if (image != null) {
-          image.autoReleaseImage();
-        }
-      }
-    }
-  }
-
-  public void autoRecoverImage(){
-    if(enableBitmapAutoManage){
-      if(isBitmapReleased){
-        WXImage image = getComponent();
-        if(image != null){
-          image.autoRecoverImage();
-        }
-        isBitmapReleased = false;
-      }
-    }
-  }
-
-
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXLoadingLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXLoadingLayout.java
deleted file mode 100644
index e4b356d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXLoadingLayout.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.content.Context;
-
-/**
- * Created by lixinke on 16/9/19.
- */
-public class WXLoadingLayout extends WXBaseRefreshLayout {
-
-  public WXLoadingLayout(Context context) {
-    super(context);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXRefreshLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXRefreshLayout.java
deleted file mode 100644
index 427adc5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXRefreshLayout.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.content.Context;
-
-/**
- * Created by lixinke on 16/9/19.
- */
-public class WXRefreshLayout extends WXBaseRefreshLayout {
-
-  public WXRefreshLayout(Context context) {
-    super(context);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXScrollView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXScrollView.java
deleted file mode 100644
index cc5b1c2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXScrollView.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.Message;
-import android.support.v4.view.NestedScrollingChild;
-import android.support.v4.view.NestedScrollingChildHelper;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ScrollView;
-
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXScroller;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXReflectionUtils;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-
-/**
- * Custom-defined scrollView
- */
-public class WXScrollView extends ScrollView implements Callback, IWXScroller,
-        WXGestureObservable,NestedScrollingChild {
-
-  private NestedScrollingChildHelper childHelper;
-  private float ox;
-  private float oy;
-  private int[] consumed = new int[2];
-  private int[] offsetInWindow = new int[2];
-
-  int mScrollX;
-  int mScrollY;
-  private WXGesture wxGesture;
-  private List<WXScrollViewListener> mScrollViewListeners;
-  private WXScroller mWAScroller;
-  //sticky
-  private View mCurrentStickyView;
-  private boolean mRedirectTouchToStickyView;
-  private int mStickyOffset;
-  private boolean mHasNotDoneActionDown = true;
-  @SuppressLint("HandlerLeak")
-  private Handler mScrollerTask;
-  private int mInitialPosition;
-  private int mCheckTime = 100;
-  /**
-   * The location of mCurrentStickyView
-   */
-  private int[] mStickyP = new int[2];
-  /**
-   * Location of the scrollView
-   */
-  private Rect mScrollRect;
-  private int[] stickyScrollerP = new int[2];
-  private int[] stickyViewP = new int[2];
-  private boolean scrollable = true;
-
-  public WXScrollView(Context context) {
-    super(context);
-    mScrollViewListeners = new ArrayList<>();
-    init();
-    try {
-      WXReflectionUtils.setValue(this, "mMinimumVelocity", 5);
-    } catch (Exception e) {
-      WXLogUtils.e("[WXScrollView] WXScrollView: ", e);
-    }
-  }
-
-  private void init() {
-    setWillNotDraw(false);
-    startScrollerTask();
-    setOverScrollMode(View.OVER_SCROLL_NEVER);
-    childHelper = new NestedScrollingChildHelper(this);
-    childHelper.setNestedScrollingEnabled(true);
-  }
-
-  public void startScrollerTask() {
-    if (mScrollerTask == null) {
-      mScrollerTask = new Handler(WXThread.secure(this));
-    }
-    mInitialPosition = getScrollY();
-    mScrollerTask.sendEmptyMessageDelayed(0, mCheckTime);
-  }
-
-  public WXScrollView(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    init();
-  }
-
-  public WXScrollView(Context context, AttributeSet attrs, int defStyle) {
-    super(context, attrs, defStyle);
-    setOverScrollMode(View.OVER_SCROLL_NEVER);
-  }
-
-  /**
-   * Add listener for scrollView.
-   */
-  public void addScrollViewListener(WXScrollViewListener scrollViewListener) {
-    if (!mScrollViewListeners.contains(scrollViewListener)) {
-      mScrollViewListeners.add(scrollViewListener);
-    }
-  }
-
-  public void removeScrollViewListener(WXScrollViewListener scrollViewListener) {
-    mScrollViewListeners.remove(scrollViewListener);
-  }
-
-  @Override
-  public boolean dispatchTouchEvent(MotionEvent ev) {
-    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-      mRedirectTouchToStickyView = true;
-    }
-
-    if (mRedirectTouchToStickyView) {
-      mRedirectTouchToStickyView = mCurrentStickyView != null;
-
-      if (mRedirectTouchToStickyView) {
-        mRedirectTouchToStickyView = ev.getY() <= mCurrentStickyView.getHeight()
-                && ev.getX() >= mCurrentStickyView.getLeft()
-                && ev.getX() <= mCurrentStickyView.getRight();
-      }
-    }
-
-    if (mRedirectTouchToStickyView) {
-      if (mScrollRect == null) {
-        mScrollRect = new Rect();
-        getGlobalVisibleRect(mScrollRect);
-      }
-      mCurrentStickyView.getLocationOnScreen(stickyViewP);
-      ev.offsetLocation(0, stickyViewP[1] - mScrollRect.top);
-    }
-    boolean result = super.dispatchTouchEvent(ev);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, ev);
-    }
-    return result;
-  }
-
-  @Override
-  protected void dispatchDraw(Canvas canvas) {
-    super.dispatchDraw(canvas);
-    if (mCurrentStickyView != null) {
-      canvas.save();
-      mCurrentStickyView.getLocationOnScreen(mStickyP);
-      int realOffset = (mStickyOffset <= 0 ? mStickyOffset : 0);
-      canvas.translate(mStickyP[0], getScrollY() + realOffset);
-      canvas.clipRect(0, realOffset, mCurrentStickyView.getWidth(),
-              mCurrentStickyView.getHeight());
-      mCurrentStickyView.draw(canvas);
-      canvas.restore();
-    }
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent ev) {
-    if(!scrollable) {
-      return true; // when scrollable is set to false, then eat the touch event
-    }
-    if (mRedirectTouchToStickyView) {
-
-      if (mScrollRect == null) {
-        mScrollRect = new Rect();
-        getGlobalVisibleRect(mScrollRect);
-      }
-      mCurrentStickyView.getLocationOnScreen(stickyViewP);
-      ev.offsetLocation(0, -(stickyViewP[1] - mScrollRect.top));
-    }
-
-    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-      mHasNotDoneActionDown = false;
-    }
-
-    if (mHasNotDoneActionDown) {
-      MotionEvent down = MotionEvent.obtain(ev);
-      down.setAction(MotionEvent.ACTION_DOWN);
-      mHasNotDoneActionDown = false;
-      down.recycle();
-    }
-
-    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-      ox = ev.getX();
-      oy = ev.getY();
-      // Dispatch touch event to parent view
-      startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL | ViewCompat.SCROLL_AXIS_VERTICAL);
-    }
-
-    if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) {
-      mHasNotDoneActionDown = true;
-      // stop nested scrolling dispatch
-      stopNestedScroll();
-    }
-
-    if (ev.getAction() == MotionEvent.ACTION_MOVE) {
-      float clampedX = ev.getX();
-      float clampedY = ev.getY();
-      int dx = (int) (ox - clampedX);
-      int dy = (int) (oy - clampedY);
-
-      if (dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)) {
-        // sub dx/dy was consumed by parent view!!!
-        ev.setLocation(clampedX+consumed[0],clampedY+consumed[1]);
-      }
-      ox = ev.getX();
-      oy = ev.getY();
-    }
-
-    return super.onTouchEvent(ev);
-  }
-
-  @Override
-  public void setNestedScrollingEnabled(boolean enabled) {
-    childHelper.setNestedScrollingEnabled(enabled);
-  }
-
-  @Override
-  public boolean isNestedScrollingEnabled() {
-    return childHelper.isNestedScrollingEnabled();
-  }
-
-  @Override
-  public boolean startNestedScroll(int axes) {
-    return childHelper.startNestedScroll(axes);
-  }
-
-  @Override
-  public void stopNestedScroll() {
-    childHelper.stopNestedScroll();
-  }
-
-  @Override
-  public boolean hasNestedScrollingParent() {
-    return childHelper.hasNestedScrollingParent();
-  }
-
-  public boolean isScrollable() {
-    return scrollable;
-  }
-
-  public void setScrollable(boolean scrollable) {
-    this.scrollable = scrollable;
-  }
-
-  @Override
-  public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
-    return childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
-  }
-
-  @Override
-  public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
-    return childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
-  }
-
-  @Override
-  public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
-    return childHelper.dispatchNestedFling(velocityX, velocityY, consumed);
-  }
-
-  @Override
-  public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
-    return childHelper.dispatchNestedPreFling(velocityX, velocityY);
-  }
-
-  @Override
-  public boolean onNestedPreFling(View target, float velocityX,
-                                  float velocityY) {
-    return dispatchNestedPreFling(velocityX, velocityY);
-  }
-
-  @Override
-  public boolean onNestedFling(View target, float velocityX, float velocityY,
-                               boolean consumed) {
-    return dispatchNestedFling(velocityX, velocityY, consumed);
-  }
-
-  @Override
-  public void fling(int velocityY) {
-    super.fling(velocityY);
-    if (mScrollerTask != null) {
-      mScrollerTask.removeMessages(0);
-    }
-    startScrollerTask();
-  }
-
-  @Override
-  protected void onScrollChanged(int x, int y, int oldx, int oldy) {
-    mScrollX = getScrollX();
-    mScrollY = getScrollY();
-    onScroll(WXScrollView.this, mScrollX, mScrollY);
-    View view = getChildAt(getChildCount() - 1);
-    if (view == null) {
-      return;
-    }
-    int d = view.getBottom();
-    d -= (getHeight() + mScrollY);
-    if (d == 0) {
-      onScrollToBottom(mScrollX, mScrollY);
-    }
-    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
-    for (int i = 0; i < count; ++i) {
-      mScrollViewListeners.get(i).onScrollChanged(this, x, y, oldx, oldy);
-    }
-
-    showStickyView();
-  }
-
-  protected void onScroll(WXScrollView scrollView, int x, int y) {
-    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
-    for (int i = 0; i < count; ++i) {
-      mScrollViewListeners.get(i).onScroll(this, x, y);
-    }
-  }
-
-  protected void onScrollToBottom(int x, int y) {
-    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
-    for (int i = 0; i < count; ++i) {
-      mScrollViewListeners.get(i).onScrollToBottom(this, x, y);
-    }
-  }
-
-  private void showStickyView() {
-    if(mWAScroller == null){
-      return;
-    }
-    View curStickyView = procSticky(mWAScroller.getStickMap());
-
-    if (curStickyView != null) {
-      mCurrentStickyView = curStickyView;
-    } else {
-      mCurrentStickyView = null;
-    }
-  }
-
-  private View procSticky(Map<String, Map<String, WXComponent>> mStickyMap) {
-    if (mStickyMap == null) {
-      return null;
-    }
-    Map<String, WXComponent> stickyMap = mStickyMap.get(mWAScroller.getRef());
-    if (stickyMap == null) {
-      return null;
-    }
-
-    Iterator<Entry<String, WXComponent>> iterator = stickyMap.entrySet().iterator();
-    Entry<String, WXComponent> entry = null;
-    WXComponent stickyData;
-    while (iterator.hasNext()) {
-      entry = iterator.next();
-      stickyData = entry.getValue();
-
-      getLocationOnScreen(stickyScrollerP);
-      stickyData.getHostView().getLocationOnScreen(stickyViewP);
-      int parentH = 0;
-      if(stickyData.getParent()!=null && stickyData.getParent().getRealView()!=null){
-        parentH=stickyData.getParent().getRealView().getHeight();
-      }
-      int stickyViewH = stickyData.getHostView().getHeight();
-      int stickyShowPos = stickyScrollerP[1];
-      int stickyStartHidePos = -parentH + stickyScrollerP[1] + stickyViewH;
-      if (stickyViewP[1] <= stickyShowPos && stickyViewP[1] >= (stickyStartHidePos - stickyViewH)) {
-        mStickyOffset = stickyViewP[1] - stickyStartHidePos;
-        stickyData.setStickyOffset(stickyViewP[1]-stickyScrollerP[1]);
-        return stickyData.getHostView();
-      }else{
-        stickyData.setStickyOffset(0);
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public boolean handleMessage(Message msg) {
-    switch (msg.what) {
-      case 0:
-        if (mScrollerTask != null) {
-          mScrollerTask.removeMessages(0);
-        }
-        int newPosition = getScrollY();
-        if (mInitialPosition - newPosition == 0) {//has stopped
-          onScrollStopped(WXScrollView.this, getScrollX(), getScrollY());
-        } else {
-          onScroll(WXScrollView.this, getScrollX(), getScrollY());
-          mInitialPosition = getScrollY();
-          if (mScrollerTask != null) {
-            mScrollerTask.sendEmptyMessageDelayed(0, mCheckTime);
-          }
-        }
-        break;
-      default:
-        break;
-    }
-    return true;
-  }
-
-  protected void onScrollStopped(WXScrollView scrollView, int x, int y) {
-    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
-    for (int i = 0; i < count; ++i) {
-      mScrollViewListeners.get(i).onScrollStopped(this, x, y);
-    }
-  }
-
-  @Override
-  public void destroy() {
-    if (mScrollerTask != null) {
-      mScrollerTask.removeCallbacksAndMessages(null);
-    }
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  public Rect getContentFrame() {
-    return new Rect(0, 0, computeHorizontalScrollRange(), computeVerticalScrollRange());
-  }
-
-  public interface WXScrollViewListener {
-
-    void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy);
-
-    void onScrollToBottom(WXScrollView scrollView, int x, int y);
-
-    void onScrollStopped(WXScrollView scrollView, int x, int y);
-
-    void onScroll(WXScrollView scrollView, int x, int y);
-  }
-
-  public void setWAScroller(WXScroller mWAScroller) {
-    this.mWAScroller = mWAScroller;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXSmoothScroller.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXSmoothScroller.java
deleted file mode 100644
index 4dfed7e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXSmoothScroller.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.view.animation.Interpolator;
-import android.widget.Scroller;
-
-/**
- * modify the scrollFactor
- */
-public class WXSmoothScroller extends Scroller {
-
-  private double mScrollFactor = 1;
-
-  public WXSmoothScroller(Context context) {
-    super(context);
-  }
-
-  public WXSmoothScroller(Context context, Interpolator interpolator) {
-    super(context, interpolator);
-  }
-
-  @SuppressLint("NewApi")
-  public WXSmoothScroller(Context context, Interpolator interpolator, boolean flywheel) {
-    super(context, interpolator, flywheel);
-  }
-
-  /**
-   * Set the factor by which the duration will change
-   */
-  public void setScrollDurationFactor(double scrollFactor) {
-    mScrollFactor = scrollFactor;
-  }
-
-  @Override
-  public void startScroll(int startX, int startY, int dx, int dy, int duration) {
-    super.startScroll(startX, startY, dx, dy, (int) (duration * mScrollFactor));
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXSwitchView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXSwitchView.java
deleted file mode 100644
index dd64e7a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXSwitchView.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.support.v7.widget.SwitchCompat;
-import android.view.Gravity;
-import android.view.MotionEvent;
-
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-
-public class WXSwitchView extends SwitchCompat implements WXGestureObservable {
-
-  private WXGesture wxGesture;
-
-  public WXSwitchView(Context context) {
-    super(context);
-    setShowText(false);
-    setGravity(Gravity.CENTER_VERTICAL);
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    boolean result = super.onTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-    return result;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXTextView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXTextView.java
deleted file mode 100644
index 73a84c9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXTextView.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.support.annotation.ColorInt;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.PopupMenu;
-import android.text.Layout;
-import android.text.TextUtils;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import com.taobao.weex.ui.component.WXText;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import java.lang.ref.WeakReference;
-
-/**
- * TextView wrapper
- */
-public class WXTextView extends View implements WXGestureObservable, IWXTextView,
-        IRenderStatus<WXText>, IRenderResult<WXText> {
-
-  private WeakReference<WXText> mWeakReference;
-  private WXGesture wxGesture;
-  private Layout textLayout;
-  private boolean mIsLabelSet = false;
-
-  public WXTextView(Context context) {
-    super(context);
-  }
-
-  @Override
-  protected void onDraw(Canvas canvas) {
-    super.onDraw(canvas);
-    canvas.save();
-    Layout layout= getTextLayout();
-    if(layout!=null){
-      canvas.translate(getPaddingLeft(),getPaddingTop());
-      layout.draw(canvas);
-    }
-    canvas.restore();
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    boolean result = super.onTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-    return result;
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  @Override
-  public CharSequence getText() {
-    return textLayout != null ? textLayout.getText() : null;
-  }
-
-  public Layout getTextLayout() {
-    return textLayout;
-  }
-
-  public void setTextLayout(Layout layout) {
-    this.textLayout = layout;
-    if(layout!=null && !mIsLabelSet){
-      setContentDescription(layout.getText());
-    }
-    if (mWeakReference != null) {
-      WXText wxText = mWeakReference.get();
-      if (wxText != null) {
-        wxText.readyToRender();
-      }
-    }
-  }
-
-  public void setAriaLabel(String label){
-    if(!TextUtils.isEmpty(label)){
-      mIsLabelSet = true;
-      setContentDescription(label);
-    }else{
-      mIsLabelSet = false;
-      if(textLayout != null){
-        setContentDescription(textLayout.getText());
-      }
-    }
-
-  }
-
-  /**
-   * Sets the text color for the text layout, it will be invalid
-   * when {@link #setTextLayout(Layout)} happens, and color has to be
-   * reset.
-   *
-   * @see #setTextLayout(Layout)
-   *
-   * @param color A color value in the form 0xAARRGGBB.
-   */
-  public void setTextColor(@ColorInt int color) {
-    Layout layout = getTextLayout();
-    if (layout != null) {
-      layout.getPaint().setColor(color);
-    }
-  }
-
-  @Override
-  public void holdComponent(WXText component) {
-    mWeakReference = new WeakReference<>(component);
-  }
-
-  @Nullable
-  @Override
-  public WXText getComponent() {
-    return null != mWeakReference ? mWeakReference.get() : null;
-  }
-
-  public void enableCopy(boolean enable) {
-    if (enable) {
-      setOnLongClickListener(new OnLongClickListener() {
-        @Override
-        public boolean onLongClick(View v) {
-          PopupMenu popupMenu = new PopupMenu(getContext(), WXTextView.this);
-          String s = "Copy";
-          try {
-            s = getContext().getResources().getString(android.R.string.copy);
-          } catch (Throwable t) {
-            //ignore
-          }
-          final String title = s;
-          popupMenu.getMenu().add(title);
-          popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
-            @Override
-            public boolean onMenuItemClick(MenuItem item) {
-              if (title.equals(item.getTitle())) {
-                String data = getText().toString();
-                ClipboardManager clipboardManager = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
-                if (clipboardManager != null) {
-                  ClipData clipData = ClipData.newPlainText(data, data);
-                  clipboardManager.setPrimaryClip(clipData);
-                }
-                return true;
-              }
-              return false;
-            }
-          });
-          popupMenu.show();
-          return true;
-        }
-      });
-    } else {
-      setOnLongClickListener(null);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXVideoView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXVideoView.java
deleted file mode 100644
index 6b671cb..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXVideoView.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Rect;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-import android.widget.MediaController;
-import android.widget.ProgressBar;
-import android.widget.VideoView;
-
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.utils.WXResourceUtils;
-
-
-public class WXVideoView extends VideoView implements WXGestureObservable {
-
-  private WXGesture wxGesture;
-  private VideoPlayListener mVideoPauseListener;
-
-  public WXVideoView(Context context) {
-    super(context);
-  }
-
-  @Override
-  public void registerGestureListener(WXGesture wxGesture) {
-    this.wxGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return wxGesture;
-  }
-
-  public void setOnVideoPauseListener(VideoPlayListener listener) {
-    mVideoPauseListener = listener;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    boolean result = super.onTouchEvent(event);
-    if (wxGesture != null) {
-      result |= wxGesture.onTouch(this, event);
-    }
-    return result;
-  }
-
-  @Override
-  public void start() {
-    super.start();
-    if (mVideoPauseListener != null) {
-      mVideoPauseListener.onStart();
-    }
-  }
-
-  @Override
-  public void pause() {
-    super.pause();
-    if (mVideoPauseListener != null) {
-      mVideoPauseListener.onPause();
-    }
-  }
-
-  public interface VideoPlayListener {
-
-    void onPause();
-
-    void onStart();
-  }
-
-
-  public static class Wrapper extends FrameLayout implements ViewTreeObserver.OnGlobalLayoutListener {
-
-    private WXVideoView mVideoView;
-    private ProgressBar mProgressBar;
-    private MediaController mMediaController;
-    private Uri mUri;
-    private MediaPlayer.OnPreparedListener mOnPreparedListener;
-    private MediaPlayer.OnErrorListener mOnErrorListener;
-    private MediaPlayer.OnCompletionListener mOnCompletionListener;
-    private WXVideoView.VideoPlayListener mVideoPlayListener;
-    private boolean mControls = true;
-
-    public Wrapper(Context context) {
-      super(context);
-      init(context);
-    }
-
-    public Wrapper(Context context, AttributeSet attrs) {
-      super(context, attrs);
-      init(context);
-    }
-
-    public Wrapper(Context context, AttributeSet attrs, int defStyleAttr) {
-      super(context, attrs, defStyleAttr);
-      init(context);
-    }
-
-    private void init(Context context) {
-      setBackgroundColor(WXResourceUtils.getColor("#ee000000"));
-      mProgressBar = new ProgressBar(context);
-      FrameLayout.LayoutParams pLayoutParams =
-              new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
-                      FrameLayout.LayoutParams.WRAP_CONTENT);
-      mProgressBar.setLayoutParams(pLayoutParams);
-      pLayoutParams.gravity = Gravity.CENTER;
-      addView(mProgressBar);
-
-      getViewTreeObserver().addOnGlobalLayoutListener(this);
-    }
-
-    public ProgressBar getProgressBar() {
-      return mProgressBar;
-    }
-
-    public
-    @Nullable
-    WXVideoView getVideoView() {
-      return mVideoView;
-    }
-
-    /**
-     * Create if not existed. Will cause request focus.
-     *
-     * @return
-     */
-    public
-    @NonNull
-    WXVideoView createIfNotExist() {
-      if (mVideoView == null) {
-        createVideoView();
-      }
-      return mVideoView;
-    }
-
-    public
-    @Nullable
-    MediaController getMediaController() {
-      return mMediaController;
-    }
-
-    public void setVideoURI(Uri uri) {
-      mUri = uri;
-      if (mVideoView != null) {
-        mVideoView.setVideoURI(uri);
-      }
-    }
-
-    public void start() {
-      if (mVideoView != null) {
-        mVideoView.start();
-      }
-    }
-
-    public void pause() {
-      if (mVideoView != null) {
-        mVideoView.pause();
-      }
-    }
-
-    public void stopPlayback() {
-      if (mVideoView != null) {
-        mVideoView.stopPlayback();
-      }
-    }
-
-    public void resume() {
-      if (mVideoView != null) {
-        mVideoView.resume();
-      }
-    }
-
-    public void setOnErrorListener(MediaPlayer.OnErrorListener l) {
-      mOnErrorListener = l;
-      if (mVideoView != null) {
-        mVideoView.setOnErrorListener(l);
-      }
-    }
-
-    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
-      mOnPreparedListener = l;
-      if (mVideoView != null) {
-        mVideoView.setOnPreparedListener(l);
-      }
-
-    }
-
-    public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) {
-      mOnCompletionListener = l;
-      if (mVideoView != null) {
-        mVideoView.setOnCompletionListener(l);
-      }
-    }
-
-    public void setOnVideoPauseListener(VideoPlayListener listener) {
-      mVideoPlayListener = listener;
-      if (mVideoView != null) {
-        mVideoView.setOnVideoPauseListener(listener);
-      }
-    }
-
-    public void setControls(boolean controls) {
-      mControls = controls;
-      if (mVideoView != null && mMediaController != null) {
-        if (!mControls) {
-          mMediaController.setVisibility(View.GONE);
-        } else {
-          mMediaController.setVisibility(View.VISIBLE);
-        }
-      }
-    }
-
-    private synchronized void createVideoView() {
-      if(mVideoView != null){
-        return;
-      }
-      Context context = getContext();
-      WXVideoView video = new WXVideoView(context);
-      FrameLayout.LayoutParams videoLayoutParams =
-              new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
-                      FrameLayout.LayoutParams.MATCH_PARENT);
-      videoLayoutParams.gravity = Gravity.CENTER;
-      video.setLayoutParams(videoLayoutParams);
-      addView(video, 0);//first child
-      video.setOnErrorListener(mOnErrorListener);
-      video.setOnPreparedListener(mOnPreparedListener);
-      video.setOnCompletionListener(mOnCompletionListener);
-      video.setOnVideoPauseListener(mVideoPlayListener);
-      MediaController controller = new MediaController(context);
-      controller.setAnchorView(this);
-      video.setMediaController(controller);
-      controller.setMediaPlayer(video);
-      if (!mControls) {
-        controller.setVisibility(View.GONE);
-      } else {
-        controller.setVisibility(View.VISIBLE);
-      }
-      mMediaController = controller;
-      mVideoView = video;
-      mVideoView.setZOrderOnTop(true);
-
-      if(mUri != null) {
-        setVideoURI(mUri);
-      }
-    }
-
-    @SuppressLint("NewApi")
-    private void removeSelfFromViewTreeObserver() {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-        getViewTreeObserver().removeOnGlobalLayoutListener(this);
-      } else {
-        getViewTreeObserver().removeGlobalOnLayoutListener(this);
-      }
-    }
-
-
-    public boolean createVideoViewIfVisible(){
-      Rect visibleRect = new Rect();
-      if (mVideoView != null) {
-        return true;
-      } else if (getGlobalVisibleRect(visibleRect) && !visibleRect.isEmpty()) {
-        createVideoView();
-        return true;
-      }
-      return false;
-    }
-
-    @Override
-    public void onGlobalLayout() {
-      if(createVideoViewIfVisible()){
-        removeSelfFromViewTreeObserver();
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java
deleted file mode 100644
index 135efc9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXWebView.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.net.Uri;
-import android.net.http.SslError;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Message;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.view.Gravity;
-import android.view.View;
-import android.webkit.JavascriptInterface;
-import android.webkit.JsPromptResult;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebChromeClient;
-import android.webkit.WebResourceError;
-import android.webkit.WebResourceRequest;
-import android.webkit.WebResourceResponse;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.FrameLayout;
-import android.widget.ProgressBar;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.ref.WeakReference;
-import java.util.HashMap;
-import java.util.Map;
-
-public class WXWebView implements IWebView {
-
-    private Context mContext;
-    private String mOrigin;
-    private WebView mWebView;
-    private ProgressBar mProgressBar;
-    private boolean mShowLoading = true;
-    private Handler mMessageHandler;
-    private static final int POST_MESSAGE = 1;
-    private static final String BRIDGE_NAME = "__WEEX_WEB_VIEW_BRIDGE";
-    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
-    // downgraded by CVE-2012-6636(https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6636)
-    private static final boolean DOWNGRADE_JS_INTERFACE = SDK_VERSION < 17;
-
-    private OnErrorListener mOnErrorListener;
-    private OnPageListener mOnPageListener;
-    private OnMessageListener mOnMessageListener;
-
-    public WXWebView(Context context, String origin) {
-        mContext = context;
-        mOrigin = origin;
-    }
-
-    @Override
-    public View getView() {
-        FrameLayout root = new FrameLayout(mContext);
-        root.setBackgroundColor(Color.WHITE);
-
-        mWebView = new WebView(mContext);//mContext.getApplicationContext();
-        FrameLayout.LayoutParams wvLayoutParams =
-                new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
-                        FrameLayout.LayoutParams.MATCH_PARENT);
-        wvLayoutParams.gravity = Gravity.CENTER;
-        mWebView.setLayoutParams(wvLayoutParams);
-        root.addView(mWebView);
-        initWebView(mWebView);
-
-        mProgressBar = new ProgressBar(mContext);
-        showProgressBar(false);
-        FrameLayout.LayoutParams pLayoutParams =
-                new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
-                        FrameLayout.LayoutParams.WRAP_CONTENT);
-        mProgressBar.setLayoutParams(pLayoutParams);
-        pLayoutParams.gravity = Gravity.CENTER;
-        root.addView(mProgressBar);
-
-        mMessageHandler = new MessageHandler(this);
-
-        return root;
-    }
-
-    @Override
-    public void destroy() {
-        if (getWebView() != null) {
-            getWebView().removeAllViews();
-            getWebView().destroy();
-            mWebView = null;
-        }
-    }
-
-    @Override
-    public void loadUrl(String url) {
-        if(getWebView() == null)
-            return;
-        getWebView().loadUrl(url);
-    }
-
-    @Override
-    public void loadDataWithBaseURL(String source) {
-        if(getWebView() == null)
-            return;
-        getWebView().loadDataWithBaseURL(mOrigin, source, "text/html", "utf-8", null);
-    }
-
-    @Override
-    public void reload() {
-        if(getWebView() == null)
-            return;
-        getWebView().reload();
-    }
-
-    @Override
-    public void goBack() {
-        if(getWebView() == null)
-            return;
-        getWebView().goBack();
-    }
-
-    @Override
-    public void goForward() {
-        if(getWebView() == null)
-            return;
-        getWebView().goForward();
-    }
-
-    @Override
-    public void postMessage(Object msg) {
-        if (getWebView() == null) return;
-
-        try {
-            JSONObject initData = new JSONObject();
-            initData.put("type", "message");
-            initData.put("data", msg);
-            initData.put("origin", mOrigin);
-            evaluateJS("javascript:(function () {"
-                + "var initData = " + initData.toString() + ";"
-                + "try {"
-                + "var event = new MessageEvent('message', initData);"
-                + "window.dispatchEvent(event);"
-                + "} catch (e) {}"
-                + "})();");
-        } catch (JSONException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /*@Override
-    public void setVisibility(int visibility) {
-        if (mRootView != null) {
-            mRootView.setVisibility(visibility);
-        }
-    }*/
-
-    @Override
-    public void setShowLoading(boolean shown) {
-        mShowLoading = shown;
-    }
-
-    @Override
-    public void setOnErrorListener(OnErrorListener listener) {
-        mOnErrorListener = listener;
-    }
-
-    @Override
-    public void setOnPageListener(OnPageListener listener) {
-        mOnPageListener = listener;
-    }
-
-    @Override
-    public void setOnMessageListener(OnMessageListener listener) {
-        mOnMessageListener = listener;
-    }
-
-    private void showProgressBar(boolean shown) {
-        if (mShowLoading) {
-            mProgressBar.setVisibility(shown ? View.VISIBLE : View.GONE);
-        }
-    }
-
-    private void showWebView(boolean shown) {
-        mWebView.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
-    }
-
-    private @Nullable WebView getWebView() {
-        //TODO: remove this, duplicate with getView semantically.
-        return mWebView;
-    }
-
-    @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"})
-    private void initWebView(WebView wv) {
-        WebSettings settings = wv.getSettings();
-        settings.setJavaScriptEnabled(true);
-        settings.setAppCacheEnabled(true);
-        settings.setUseWideViewPort(true);
-        settings.setDomStorageEnabled(true);
-        settings.setSupportZoom(false);
-        settings.setBuiltInZoomControls(false);
-        settings.setAllowFileAccess(false);
-        wv.setWebViewClient(new WebViewClient() {
-
-            @Override
-            public boolean shouldOverrideUrlLoading(WebView view, String url) {
-                view.loadUrl(url);
-                WXLogUtils.v("tag", "onPageOverride " + url);
-                return true;
-            }
-
-            @Override
-            public void onPageStarted(WebView view, String url, Bitmap favicon) {
-                super.onPageStarted(view, url, favicon);
-                WXLogUtils.v("tag", "onPageStarted " + url);
-                if (mOnPageListener != null) {
-                    mOnPageListener.onPageStart(url);
-                }
-            }
-
-            @Override
-            public void onPageFinished(WebView view, String url) {
-                super.onPageFinished(view, url);
-                WXLogUtils.v("tag", "onPageFinished " + url);
-                if (mOnPageListener != null) {
-                    mOnPageListener.onPageFinish(url, view.canGoBack(), view.canGoForward());
-                }
-                if (mOnMessageListener != null) {
-                    evaluateJS("javascript:(window.postMessage = function(message, targetOrigin) {"
-                        + "if (message == null || !targetOrigin) return;"
-                        + (DOWNGRADE_JS_INTERFACE
-                        ? "prompt('" + BRIDGE_NAME + "://postMessage?message=' + JSON.stringify(message) + '&targetOrigin=' + targetOrigin)"
-                        : BRIDGE_NAME + ".postMessage(JSON.stringify(message), targetOrigin);")
-                        + "})");
-                }
-            }
-
-            @Override
-            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
-                super.onReceivedError(view, request, error);
-                if (mOnErrorListener != null) {
-                    //mOnErrorListener.onError("error", "page error code:" + error.getErrorCode() + ", desc:" + error.getDescription() + ", url:" + request.getUrl());
-                    mOnErrorListener.onError("error", "page error");
-                }
-            }
-
-            @Override
-            public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
-                super.onReceivedHttpError(view, request, errorResponse);
-                if (mOnErrorListener != null) {
-                    mOnErrorListener.onError("error", "http error");
-                }
-            }
-
-            @Override
-            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-                super.onReceivedSslError(view, handler, error);
-                if (mOnErrorListener != null) {
-                    mOnErrorListener.onError("error", "ssl error");
-                }
-            }
-        });
-        wv.setWebChromeClient(new WebChromeClient() {
-            @Override
-            public void onProgressChanged(WebView view, int newProgress) {
-                super.onProgressChanged(view, newProgress);
-                showWebView(newProgress == 100);
-                showProgressBar(newProgress != 100);
-                WXLogUtils.v("tag", "onPageProgressChanged " + newProgress);
-            }
-
-            @Override
-            public void onReceivedTitle(WebView view, String title) {
-                super.onReceivedTitle(view, title);
-                if (mOnPageListener != null) {
-                    mOnPageListener.onReceivedTitle(view.getTitle());
-                }
-            }
-
-            @Override
-            public boolean onJsPrompt(WebView view, String url, String text, String defaultValue, JsPromptResult result) {
-                Uri uri = Uri.parse(text);
-                String scheme = uri.getScheme();
-                if (TextUtils.equals(scheme, BRIDGE_NAME)) {
-                    if (TextUtils.equals(uri.getAuthority(), "postMessage")) {
-                        String message = uri.getQueryParameter("message");
-                        String targetOrigin = uri.getQueryParameter("targetOrigin");
-                        onMessage(message, targetOrigin);
-                        result.confirm("success");
-                    } else {
-                        result.confirm("fail");
-                    }
-                    return true;
-                }
-                return super.onJsPrompt(view, url, text, defaultValue, result);
-            }
-        });
-        if (!DOWNGRADE_JS_INTERFACE) {
-            wv.addJavascriptInterface(new Object() {
-                @JavascriptInterface
-                public void postMessage(String message, String targetOrigin) {
-                    onMessage(message, targetOrigin);
-                }
-            }, BRIDGE_NAME);
-        }
-    }
-
-    private void onMessage(String message, String targetOrigin) {
-        if (message != null && targetOrigin != null && mOnMessageListener != null) {
-            try {
-                Map<String, Object> initData = new HashMap<>();
-                initData.put("data", JSON.parse(message));
-                initData.put("origin", targetOrigin);
-                initData.put("type", "message");
-                Message threadMessage = new Message();
-                threadMessage.what = POST_MESSAGE;
-                threadMessage.obj = initData;
-                mMessageHandler.sendMessage(threadMessage);
-            } catch (JSONException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
-    private void evaluateJS(String jsStr) {
-        if (SDK_VERSION < 19) {
-            mWebView.loadUrl(jsStr);
-        } else {
-            mWebView.evaluateJavascript(jsStr, null);
-        }
-    }
-
-    private static class MessageHandler extends Handler {
-        private final WeakReference<WXWebView> mWv;
-
-        private MessageHandler(WXWebView wv) {
-            mWv = new WeakReference<>(wv);
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public void handleMessage(Message msg) {
-            super.handleMessage(msg);
-            switch (msg.what) {
-                case POST_MESSAGE:
-                    if (mWv.get() != null && mWv.get().mOnMessageListener != null) {
-                        mWv.get().mOnMessageListener.onMessage((Map<String, Object>) msg.obj);
-                    }
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderCorner.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderCorner.java
deleted file mode 100644
index 918d2f0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderCorner.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.support.annotation.NonNull;
-import com.taobao.weex.base.FloatUtil;
-
-abstract class BorderCorner {
-
-  final static float SWEEP_ANGLE = 45;
-  private float mCornerRadius = 0.0f;
-  private float mPreBorderWidth = 0.0f;
-  private float mPostBorderWidth = 0.0f;
-  private RectF mBorderBox;
-  protected float mAngleBisector;
-
-  /**
-   * Tell whether this corner has a rounded inner corner.
-   * If a corner has a rounded inner corner, it has an outer corner as well.
-   */
-  private boolean hasInnerCorner = false;
-
-  /**
-   * Tell whether this corner has a rounded outer corner.
-   */
-  private boolean hasOuterCorner = false;
-
-  private float mOvalLeft, mOvalTop, mOvalRight, mOvalBottom;
-
-  private float mRoundCornerStartX, mRoundCornerStartY;
-  private float mRoundCornerEndX, mRoundCornerEndY;
-
-  BorderCorner() {
-  }
-
-  final void set(float cornerRadius, float preBorderWidth, float postBorderWidth,
-                 @NonNull RectF borderBox, float angleBisector) {
-    boolean dirty = !FloatUtil.floatsEqual(mCornerRadius, cornerRadius)
-        || !FloatUtil.floatsEqual(mPreBorderWidth, preBorderWidth)
-        || !FloatUtil.floatsEqual(mPostBorderWidth, postBorderWidth)
-        || !FloatUtil.floatsEqual(mAngleBisector, angleBisector)
-        || (null != mBorderBox && mBorderBox.equals(borderBox));
-
-    if (dirty) {
-      mCornerRadius = cornerRadius;
-      mPreBorderWidth = preBorderWidth;
-      mPostBorderWidth = postBorderWidth;
-      mBorderBox = borderBox;
-      mAngleBisector = angleBisector;
-
-      hasOuterCorner = mCornerRadius > 0 && !FloatUtil.floatsEqual(0, mCornerRadius);
-
-      hasInnerCorner = (hasOuterCorner
-          && (getPreBorderWidth() >= 0)
-          && (getPostBorderWidth() >= 0)
-          && (getOuterCornerRadius() > getPreBorderWidth())
-          && (getOuterCornerRadius() > getPostBorderWidth()));
-
-      if (hasOuterCorner) {
-        prepareOval();
-      }
-      prepareRoundCorner();
-    }
-  }
-
-  /** Build oval data */
-  abstract protected void prepareOval();
-
-  /** Build corner data */
-  abstract protected void prepareRoundCorner();
-
-  public final void drawRoundedCorner(@NonNull Canvas canvas, @NonNull Paint paint, float startAngle) {
-    if (this.hasOuterCorner()) {
-      /*Due to the problem of hardware-acceleration, border-radius in some case will not
-       be rendered if Path.addArc used instead and the following condition met.
-       1. hardware-acceleration enabled
-       2. System version is Android 4.1
-       3. Screen width is 720px.
-       http://dotwe.org/weex/421b9ad09fde51c0b49bb56b37fcf955
-      */
-      if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
-        canvas.drawArc(mOvalLeft, mOvalTop, mOvalRight, mOvalBottom, startAngle, BorderCorner.SWEEP_ANGLE, false,
-            paint);
-      } else {
-        canvas.drawArc(new RectF(mOvalLeft, mOvalTop, mOvalRight, mOvalBottom), startAngle, BorderCorner.SWEEP_ANGLE,
-            false, paint);
-      }
-    } else {
-      canvas.drawLine(getRoundCornerStartX(), getRoundCornerStartY(), getRoundCornerEndX(), getRoundCornerEndY(),
-          paint);
-    }
-  }
-
-
-  public final float getRoundCornerStartX() {
-    return mRoundCornerStartX;
-  }
-
-  final void setRoundCornerStartX(float roundCornerStartX) {
-    this.mRoundCornerStartX = roundCornerStartX;
-  }
-
-  public final float getRoundCornerStartY() {
-    return mRoundCornerStartY;
-  }
-
-  final void setRoundCornerStartY(float roundCornerStartY) {
-    this.mRoundCornerStartY = roundCornerStartY;
-  }
-
-  public final float getRoundCornerEndX() {
-    return mRoundCornerEndX;
-  }
-
-  final void setRoundCornerEndX(float mRoundCornerEndX) {
-    this.mRoundCornerEndX = mRoundCornerEndX;
-  }
-
-  public final float getRoundCornerEndY() {
-    return mRoundCornerEndY;
-  }
-
-  final void setRoundCornerEndY(float mRoundCornerEndY) {
-    this.mRoundCornerEndY = mRoundCornerEndY;
-  }
-
-  final void setOvalLeft(float mOvalLeft) {
-    this.mOvalLeft = mOvalLeft;
-  }
-
-  final void setOvalTop(float mOvalTop) {
-    this.mOvalTop = mOvalTop;
-  }
-
-  final void setOvalRight(float mOvalRight) {
-    this.mOvalRight = mOvalRight;
-  }
-
-  final void setOvalBottom(float mOvalBottom) {
-    this.mOvalBottom = mOvalBottom;
-  }
-
-  /**
-   * Tell whether this corner has a rounded inner corner.
-   * If a corner has a rounded inner corner, it has an outer corner as well.
-   * @return true for a rounded inner corner, otherwise false.
-   */
-  boolean hasInnerCorner() {
-    return hasInnerCorner;
-  }
-
-  /**
-   * Tell whether this corner has a rounded outer corner.
-   * @return true for a rounded outer corner, otherwise false.
-   */
-  boolean hasOuterCorner() {
-    return hasOuterCorner;
-  }
-
-  protected final float getPreBorderWidth() {
-    return mPreBorderWidth;
-  }
-
-  protected final float getPostBorderWidth() {
-    return mPostBorderWidth;
-  }
-
-  protected final float getOuterCornerRadius() {
-    return mCornerRadius;
-  }
-
-  protected final float getAngleBisectorDegree(){
-    return mAngleBisector;
-  }
-
-  protected final RectF getBorderBox() {
-    return mBorderBox;
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java
deleted file mode 100644
index e4c0dfb..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.util.SparseIntArray;
-import com.taobao.weex.dom.CSSShorthand;
-import com.taobao.weex.dom.CSSShorthand.CORNER;
-import com.taobao.weex.dom.CSSShorthand.EDGE;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXViewUtils;
-
-import static com.taobao.weex.dom.CSSShorthand.CORNER.ALL;
-import static com.taobao.weex.dom.CSSShorthand.CORNER.BORDER_BOTTOM_LEFT;
-import static com.taobao.weex.dom.CSSShorthand.CORNER.BORDER_BOTTOM_RIGHT;
-import static com.taobao.weex.dom.CSSShorthand.CORNER.BORDER_TOP_LEFT;
-import static com.taobao.weex.dom.CSSShorthand.CORNER.BORDER_TOP_RIGHT;
-
-/**
- * A subclass of
- * {@link Drawable} used for background of {@link com.taobao.weex.ui.component.WXComponent}.
- * It supports drawing background color and borders (including rounded borders) by providing a react
- * friendly API (setter for each of those properties). The implementation tries to allocate as few
- * objects as possible depending on which properties are set. E.g. for views with rounded
- * background/borders we allocate {@code mPathForBorderDrawn} and {@code mTempRectForBorderRadius}.
- * In case when view have a rectangular borders we allocate {@code mBorderWidthResult} and similar.
- * When only background color is set we won't allocate any extra/unnecessary objects.
- */
-public class BorderDrawable extends Drawable {
-
-  public static final int BORDER_TOP_LEFT_RADIUS = 0;
-  public static final int BORDER_TOP_RIGHT_RADIUS = 1;
-  public static final int BORDER_BOTTOM_RIGHT_RADIUS = 2;
-  public static final int BORDER_BOTTOM_LEFT_RADIUS = 3;
-  public static final int BORDER_RADIUS_ALL = 5;
-  static final int DEFAULT_BORDER_COLOR = Color.BLACK;
-  static final float DEFAULT_BORDER_WIDTH = 0;
-  private static final BorderStyle DEFAULT_BORDER_STYLE = BorderStyle.SOLID;
-  private static final String TAG = "Border";
-  private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-  private static BorderStyle[] sBorderStyle = BorderStyle.values();
-
-  private
-  @Nullable
-  CSSShorthand<EDGE> mBorderWidth;
-  private
-  @Nullable
-  CSSShorthand<CORNER> mBorderRadius;
-  private
-  @Nullable
-  CSSShorthand<CORNER> mOverlappingBorderRadius;
-  private
-  @Nullable
-  SparseIntArray mBorderColor;
-  private
-  @Nullable
-  SparseIntArray mBorderStyle;
-
-  private
-  @Nullable
-  Path mPathForBorderOutline;
-  private boolean mNeedUpdatePath = false;
-  private int mColor = Color.TRANSPARENT;
-  /**
-   * set background-image linear-gradient
-   */
-  private Shader mShader = null;
-  private int mAlpha = 255;
-
-  private TopLeftCorner mTopLeftCorner;
-  private TopRightCorner mTopRightCorner;
-  private BottomRightCorner mBottomRightCorner;
-  private BottomLeftCorner mBottomLeftCorner;
-
-  private final BorderEdge mBorderEdge = new BorderEdge();
-
-  private RectF mRectBounds;
-
-  public BorderDrawable() {
-  }
-
-  @Override
-  public void draw(@NonNull Canvas canvas) {
-    canvas.save();
-    updateBorderOutline();
-    //Shader uses alpha as well.
-    mPaint.setAlpha(255);
-    if (mPathForBorderOutline != null) {
-      int useColor = WXViewUtils.multiplyColorAlpha(mColor, mAlpha);
-      if (mShader != null) {
-        mPaint.setShader(mShader);
-        mPaint.setStyle(Paint.Style.FILL);
-        canvas.drawPath(mPathForBorderOutline, mPaint);
-        mPaint.setShader(null);
-      } else if ((useColor >>> 24) != 0) {
-        mPaint.setColor(useColor);
-        mPaint.setStyle(Paint.Style.FILL);
-        canvas.drawPath(mPathForBorderOutline, mPaint);
-        mPaint.setShader(null);
-      }
-    }
-    mPaint.setStyle(Paint.Style.STROKE);
-    mPaint.setStrokeJoin(Paint.Join.ROUND);
-    drawBorders(canvas);
-    mPaint.setShader(null);
-    canvas.restore();
-  }
-
-  @Override
-  protected void onBoundsChange(Rect bounds) {
-    super.onBoundsChange(bounds);
-    mNeedUpdatePath = true;
-  }
-
-  @Override
-  public void setAlpha(int alpha) {
-    if (alpha != mAlpha) {
-      mAlpha = alpha;
-      invalidateSelf();
-    }
-  }
-
-  @Override
-  public int getAlpha() {
-    return mAlpha;
-  }
-
-  /**
-   * Do not support Color Filter
-   */
-  @Override
-  public void setColorFilter(ColorFilter cf) {
-
-  }
-
-  @Override
-  public int getOpacity() {
-    return mShader != null ? PixelFormat.OPAQUE :
-            WXViewUtils.getOpacityFromColor(WXViewUtils.multiplyColorAlpha(mColor, mAlpha));
-  }
-
-  /* Android's elevation implementation requires this to be implemented to know where to draw the
- shadow. */
-  @Override
-  public void getOutline(@NonNull Outline outline) {
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-      if (mPathForBorderOutline == null) {
-        mNeedUpdatePath = true;
-      }
-      updateBorderOutline();
-      outline.setConvexPath(mPathForBorderOutline);
-    }
-  }
-
-  public void setBorderWidth(CSSShorthand.EDGE edge, float width) {
-    if (mBorderWidth == null) {
-      mBorderWidth = new CSSShorthand<>();
-    }
-    if (mBorderWidth.get(edge) != width) {
-      mBorderWidth.set(edge, width);
-      mNeedUpdatePath = true;
-      invalidateSelf();
-    }
-  }
-
-  float getBorderWidth(CSSShorthand.EDGE edge) {
-    return mBorderWidth.get(edge);
-  }
-
-  public void setBorderRadius(CORNER position, float radius) {
-    if (mBorderRadius == null) {
-      mBorderRadius = new CSSShorthand<>();
-    }
-    if (mBorderRadius.get(position) != radius ||
-        (position == ALL &&
-            (radius != mBorderRadius.get(BORDER_TOP_LEFT) ||
-            radius != mBorderRadius.get(BORDER_TOP_RIGHT) ||
-            radius != mBorderRadius.get(BORDER_BOTTOM_RIGHT) ||
-            radius != mBorderRadius.get(BORDER_BOTTOM_LEFT)))) {
-      mBorderRadius.set(position, radius);
-      mNeedUpdatePath = true;
-      invalidateSelf();
-    }
-  }
-
-  public
-  @NonNull
-  float[] getBorderRadius(RectF borderBox) {
-    prepareBorderRadius(borderBox);
-    if (mOverlappingBorderRadius == null) {
-      mOverlappingBorderRadius = new CSSShorthand<>();
-    }
-    float topLeftRadius = mOverlappingBorderRadius.get(BORDER_TOP_LEFT);
-    float topRightRadius = mOverlappingBorderRadius.get(BORDER_TOP_RIGHT);
-    float bottomRightRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_RIGHT);
-    float bottomLeftRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_LEFT);
-    return new float[]{topLeftRadius, topLeftRadius,
-            topRightRadius, topRightRadius,
-            bottomRightRadius, bottomRightRadius,
-            bottomLeftRadius, bottomLeftRadius};
-  }
-
-  public
-  @NonNull
-  float[] getBorderInnerRadius(RectF borderBox) {
-    prepareBorderRadius(borderBox);
-    if (mOverlappingBorderRadius == null) {
-      mOverlappingBorderRadius = new CSSShorthand<>();
-    }
-    float topLeftRadius = mOverlappingBorderRadius.get(BORDER_TOP_LEFT);
-    float topRightRadius = mOverlappingBorderRadius.get(BORDER_TOP_RIGHT);
-    float bottomRightRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_RIGHT);
-    float bottomLeftRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_LEFT);
-    if (null != mBorderWidth) {
-      topLeftRadius = Math.max(topLeftRadius - mBorderWidth.get(EDGE.TOP), 0);
-      topRightRadius = Math.max(topRightRadius - mBorderWidth.get(EDGE.TOP), 0);
-      bottomRightRadius = Math.max(bottomRightRadius - mBorderWidth.get(EDGE.BOTTOM), 0);
-      bottomLeftRadius = Math.max(bottomLeftRadius - mBorderWidth.get(EDGE.BOTTOM), 0);
-    }
-    return new float[] {topLeftRadius, topLeftRadius,
-        topRightRadius, topRightRadius,
-        bottomRightRadius, bottomRightRadius,
-        bottomLeftRadius, bottomLeftRadius};
-  }
-
-  public void setBorderColor(CSSShorthand.EDGE edge, int color) {
-    if (mBorderColor == null) {
-      mBorderColor = new SparseIntArray(5);
-      mBorderColor.put(CSSShorthand.EDGE.ALL.ordinal(), DEFAULT_BORDER_COLOR);
-    }
-    if (getBorderColor(edge) != color) {
-      BorderUtil.updateSparseArray(mBorderColor, edge.ordinal(), color);
-      invalidateSelf();
-    }
-  }
-
-  int getBorderColor(CSSShorthand.EDGE edge) {
-    return BorderUtil.fetchFromSparseArray(mBorderColor, edge.ordinal(), DEFAULT_BORDER_COLOR);
-  }
-
-  public void setBorderStyle(CSSShorthand.EDGE edge, @NonNull String style) {
-    if (mBorderStyle == null) {
-      mBorderStyle = new SparseIntArray(5);
-      mBorderStyle.put(CSSShorthand.EDGE.ALL.ordinal(), DEFAULT_BORDER_STYLE.ordinal());
-    }
-    try {
-      int borderStyle = BorderStyle.valueOf(style.toUpperCase(Locale.US)).ordinal();
-      if (getBorderStyle(edge) != borderStyle) {
-        BorderUtil.updateSparseArray(mBorderStyle, edge.ordinal(), borderStyle);
-        invalidateSelf();
-      }
-    } catch (IllegalArgumentException e) {
-      WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
-    }
-  }
-
-  int getBorderStyle(CSSShorthand.EDGE edge) {
-    return BorderUtil.fetchFromSparseArray(mBorderStyle, edge.ordinal(), BorderStyle.SOLID.ordinal());
-  }
-
-  public int getColor() {
-    return mColor;
-  }
-
-  public void setColor(int color) {
-    mColor = color;
-    invalidateSelf();
-  }
-
-  public void setImage(Shader shader) {
-    mShader = shader;
-    invalidateSelf();
-  }
-
-  public boolean hasImage() {
-    return mShader != null;
-  }
-
-  public boolean isRounded() {
-    return mBorderRadius != null &&
-            (mBorderRadius.get(BORDER_TOP_LEFT) != 0 ||
-                mBorderRadius.get(BORDER_TOP_RIGHT) != 0 ||
-                mBorderRadius.get(BORDER_BOTTOM_RIGHT) != 0 ||
-                mBorderRadius.get(BORDER_BOTTOM_LEFT) != 0);
-  }
-
-  public
-  @NonNull
-  Path getContentPath(@NonNull RectF borderBox) {
-    Path contentClip = new Path();
-    prepareBorderPath(0, 0, 0, 0, borderBox, contentClip);
-    return contentClip;
-  }
-
-  private void updateBorderOutline() {
-    if (mNeedUpdatePath) {
-      mNeedUpdatePath = false;
-      if (mPathForBorderOutline == null) {
-        mPathForBorderOutline = new Path();
-      }
-      mPathForBorderOutline.reset();
-      prepareBorderPath(0, 0, 0, 0, new RectF(getBounds()), mPathForBorderOutline);
-    }
-  }
-
-  private void prepareBorderPath(int topPadding,
-                                 int rightPadding,
-                                 int bottomPadding,
-                                 int leftPadding,
-                                 @NonNull RectF rectF,
-                                 @NonNull Path path) {
-    if (mBorderRadius != null) {
-      prepareBorderRadius(rectF);
-      if (mOverlappingBorderRadius == null) {
-        mOverlappingBorderRadius = new CSSShorthand<>();
-      }
-      float topLeftRadius = mOverlappingBorderRadius.get(BORDER_TOP_LEFT);
-      float topRightRadius = mOverlappingBorderRadius.get(BORDER_TOP_RIGHT);
-      float bottomRightRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_RIGHT);
-      float bottomLeftRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_LEFT);
-      path.addRoundRect(
-              rectF,
-              new float[]{
-                      topLeftRadius - leftPadding,
-                      topLeftRadius - topPadding,
-                      topRightRadius - rightPadding,
-                      topRightRadius - topPadding,
-                      bottomRightRadius - rightPadding,
-                      bottomRightRadius - bottomPadding,
-                      bottomLeftRadius - leftPadding,
-                      bottomLeftRadius - bottomPadding
-              },
-              Path.Direction.CW);
-    } else {
-      path.addRect(rectF, Path.Direction.CW);
-    }
-  }
-
-  /**
-   * Process overlapping curve according to https://www.w3.org/TR/css3-background/#corner-overlap .
-   */
-  private void prepareBorderRadius(@NonNull RectF borderBox) {
-    if (mBorderRadius != null) {
-      float factor = getScaleFactor(borderBox);
-      if (mOverlappingBorderRadius == null) {
-        mOverlappingBorderRadius = new CSSShorthand<>();
-      }
-      if (!Float.isNaN(factor) && factor < 1) {
-        mOverlappingBorderRadius.set(BORDER_TOP_LEFT,
-            mBorderRadius.get(BORDER_TOP_LEFT) * factor);
-        mOverlappingBorderRadius.set(BORDER_TOP_RIGHT,
-            mBorderRadius.get(BORDER_TOP_RIGHT) * factor);
-        mOverlappingBorderRadius.set(BORDER_BOTTOM_RIGHT,
-            mBorderRadius.get(BORDER_BOTTOM_RIGHT) * factor);
-        mOverlappingBorderRadius.set(BORDER_BOTTOM_LEFT,
-            mBorderRadius.get(BORDER_BOTTOM_LEFT) * factor);
-      } else {
-        mOverlappingBorderRadius.set(BORDER_TOP_LEFT,
-            mBorderRadius.get(BORDER_TOP_LEFT));
-        mOverlappingBorderRadius.set(BORDER_TOP_RIGHT,
-            mBorderRadius.get(BORDER_TOP_RIGHT));
-        mOverlappingBorderRadius.set(BORDER_BOTTOM_RIGHT,
-            mBorderRadius.get(BORDER_BOTTOM_RIGHT));
-        mOverlappingBorderRadius.set(BORDER_BOTTOM_LEFT,
-            mBorderRadius.get(BORDER_BOTTOM_LEFT));
-      }
-    }
-  }
-
-  private float getScaleFactor(@NonNull RectF borderBox) {
-    final float topRadius = mBorderRadius.get(BORDER_TOP_LEFT)
-            + mBorderRadius.get(BORDER_TOP_RIGHT);
-    final float rightRadius = mBorderRadius.get(BORDER_TOP_RIGHT)
-            + mBorderRadius.get(BORDER_BOTTOM_RIGHT);
-    final float bottomRadius = mBorderRadius.get(BORDER_BOTTOM_RIGHT)
-            + mBorderRadius.get(BORDER_BOTTOM_LEFT);
-    final float leftRadius = mBorderRadius.get(BORDER_BOTTOM_LEFT)
-            + mBorderRadius.get(BORDER_TOP_LEFT);
-    List<Float> factors = new ArrayList<>(4);
-    updateFactor(factors, borderBox.width(), topRadius);
-    updateFactor(factors, borderBox.height(), rightRadius);
-    updateFactor(factors, borderBox.width(), bottomRadius);
-    updateFactor(factors, borderBox.height(), leftRadius);
-    float factor;
-    if (factors.isEmpty()) {
-      factor = Float.NaN;
-    } else {
-      factor = Collections.min(factors);
-    }
-    return factor;
-  }
-
-  private void updateFactor(@NonNull List<Float> list, float numerator, float denominator) {
-    if (denominator != 0) {
-      list.add(numerator / denominator);
-    }
-  }
-
-  private void drawBorders(Canvas canvas) {
-    if (mRectBounds == null) {
-      mRectBounds = new RectF(getBounds());
-    } else {
-      mRectBounds.set(getBounds());
-    }
-
-    if (mBorderWidth == null)
-      return;
-
-    final float leftBorderWidth = mBorderWidth.get(EDGE.LEFT);
-    final float topBorderWidth = mBorderWidth.get(EDGE.TOP);
-    final float bottomBorderWidth = mBorderWidth.get(EDGE.BOTTOM);
-    final float rightBorderWidth = mBorderWidth.get(EDGE.RIGHT);
-
-    if (mTopLeftCorner == null) {
-      mTopLeftCorner = new TopLeftCorner();
-    }
-    mTopLeftCorner.set(getBorderRadius(BORDER_TOP_LEFT), leftBorderWidth, topBorderWidth, mRectBounds);
-    if (mTopRightCorner == null) {
-      mTopRightCorner = new TopRightCorner();
-    }
-    mTopRightCorner.set(getBorderRadius(BORDER_TOP_RIGHT), topBorderWidth, rightBorderWidth, mRectBounds);
-    if (mBottomRightCorner == null) {
-      mBottomRightCorner = new BottomRightCorner();
-    }
-    mBottomRightCorner.set(getBorderRadius(BORDER_BOTTOM_RIGHT), rightBorderWidth, bottomBorderWidth, mRectBounds);
-    if (mBottomLeftCorner == null) {
-      mBottomLeftCorner = new BottomLeftCorner();
-    }
-    mBottomLeftCorner.set(getBorderRadius(BORDER_BOTTOM_LEFT), bottomBorderWidth, leftBorderWidth, mRectBounds);
-
-    drawOneSide(canvas, mBorderEdge.set(mTopLeftCorner, mTopRightCorner, topBorderWidth, EDGE.TOP));
-    drawOneSide(canvas, mBorderEdge.set(mTopRightCorner, mBottomRightCorner, rightBorderWidth, EDGE.RIGHT));
-    drawOneSide(canvas, mBorderEdge.set(mBottomRightCorner, mBottomLeftCorner, bottomBorderWidth, EDGE.BOTTOM));
-    drawOneSide(canvas, mBorderEdge.set(mBottomLeftCorner, mTopLeftCorner, leftBorderWidth, EDGE.LEFT));
-  }
-
-  private float getBorderRadius(CORNER position) {
-    if (null != mOverlappingBorderRadius) {
-      return mOverlappingBorderRadius.get(position);
-    } else {
-      return 0.0f;
-    }
-  }
-
-  private void drawOneSide(Canvas canvas, @NonNull BorderEdge borderEdge) {
-    if (0 != borderEdge.getBorderWidth()) {
-      preparePaint(borderEdge.getEdge());
-      borderEdge.drawEdge(canvas, mPaint);
-    }
-  }
-
-  private void preparePaint(CSSShorthand.EDGE edge) {
-    final float borderWidth = mBorderWidth.get(edge);
-    final int color = WXViewUtils.multiplyColorAlpha(getBorderColor(edge), mAlpha);
-    final BorderStyle borderStyle = sBorderStyle[getBorderStyle(edge)];
-    final Shader shader = borderStyle.getLineShader(borderWidth, color, edge);
-    mPaint.setShader(shader);
-    mPaint.setColor(color);
-    mPaint.setStrokeCap(Paint.Cap.ROUND);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderEdge.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderEdge.java
deleted file mode 100644
index 76c4e95..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderEdge.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PointF;
-import android.support.annotation.NonNull;
-import com.taobao.weex.dom.CSSShorthand;
-
-/**
- * Edge for border. Every border has four edges, and each edge has a previous corner and a post
- * corner.
- */
-class BorderEdge {
-
-  private
-  @NonNull
-  BorderCorner mPreCorner;
-  private
-  @NonNull
-  BorderCorner mPostCorner;
-
-  private CSSShorthand.EDGE mEdge;
-  private float mBorderWidth;
-
-  BorderEdge() {
-  }
-
-  BorderEdge set(@NonNull BorderCorner preCorner, @NonNull BorderCorner postCorner,
-                 float borderWidth, CSSShorthand.EDGE edge) {
-    mPreCorner = preCorner;
-    mPostCorner = postCorner;
-    mBorderWidth = borderWidth;
-    mEdge = edge;
-    return this;
-  }
-
-  /**
-   * Draw the edge on the canvas with the specified paint.
-   * @param canvas the canvas where the edge will be drawn.
-   * @param paint the paint which is used to draw.
-   */
-  void drawEdge(@NonNull Canvas canvas, @NonNull Paint paint) {
-    paint.setStrokeWidth(mBorderWidth);
-
-    mPreCorner.drawRoundedCorner(canvas, paint, mPreCorner.getAngleBisectorDegree());
-
-    paint.setStrokeWidth(mBorderWidth);
-
-    final float lineStartX = mPreCorner.getRoundCornerEndX();
-    final float lineStartY = mPreCorner.getRoundCornerEndY();
-
-    final float lineEndX = mPostCorner.getRoundCornerStartX();
-    final float lineEndY = mPostCorner.getRoundCornerStartY();
-
-    canvas.drawLine(lineStartX, lineStartY, lineEndX, lineEndY, paint);
-
-    mPostCorner.drawRoundedCorner(canvas, paint, mPostCorner.getAngleBisectorDegree() - BorderCorner.SWEEP_ANGLE);
-  }
-
-  /**
-   * The index of the edge
-   * @return index of edge. May be one of
-   */
-  public CSSShorthand.EDGE getEdge() {
-    return mEdge;
-  }
-
-  public float getBorderWidth() {
-    return mBorderWidth;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderRadiusType.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderRadiusType.java
deleted file mode 100644
index 930ef14..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderRadiusType.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.support.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-@Retention(RetentionPolicy.SOURCE)
-@IntDef({
-    BorderDrawable.BORDER_TOP_LEFT_RADIUS,
-    BorderDrawable.BORDER_TOP_RIGHT_RADIUS,
-    BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS,
-    BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS,
-    BorderDrawable.BORDER_RADIUS_ALL})
-public @interface BorderRadiusType {
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderStyle.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderStyle.java
deleted file mode 100644
index 91f4ad7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderStyle.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.PathEffect;
-import android.graphics.Shader;
-import android.support.annotation.Nullable;
-import com.taobao.weex.dom.CSSShorthand;
-
-enum BorderStyle {
-  SOLID,
-  DASHED,
-  DOTTED;
-
-  /**
-   * Use {@link LinearGradient} to replace {@link PathEffect}
-   * for implementing {@link #DASHED} or {@link #DASHED}
-   * @param borderWidth width of the edge
-   * @param borderColor color of the edge
-   * @param edge the index of the ede. See {@link CSSShorthand}
-   * @return An object of {@link LinearGradient} without color transitions for {@link #DOTTED}
-   * or {@link #DASHED}, null otherwise
-   */
-  @Nullable
-  Shader getLineShader(float borderWidth, int borderColor, CSSShorthand.EDGE edge) {
-    switch (this) {
-      case DOTTED:
-        if (edge == CSSShorthand.EDGE.LEFT || edge == CSSShorthand.EDGE.RIGHT) {
-          return new LinearGradient(0, 0, 0, borderWidth * 2, new int[]{borderColor, Color
-                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
-        } else if (edge == CSSShorthand.EDGE.TOP || edge == CSSShorthand.EDGE.BOTTOM) {
-          return new LinearGradient(0, 0, borderWidth * 2, 0, new int[]{borderColor, Color
-                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
-        }
-      case DASHED:
-        if (edge == CSSShorthand.EDGE.LEFT || edge == CSSShorthand.EDGE.RIGHT) {
-          return new LinearGradient(0, 0, 0, borderWidth * 6, new int[]{borderColor, Color
-                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
-        } else if (edge == CSSShorthand.EDGE.TOP || edge == CSSShorthand.EDGE.BOTTOM) {
-          return new LinearGradient(0, 0, borderWidth * 6, 0, new int[]{borderColor, Color
-                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
-        }
-      default:
-        return null;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderUtil.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderUtil.java
deleted file mode 100644
index 9779dbe..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderUtil.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import com.taobao.weex.dom.CSSShorthand;
-
-class BorderUtil {
-
-  static int fetchFromSparseArray(@Nullable SparseIntArray array, int position, int fallback) {
-    return array == null ? fallback :
-            array.get(position, array.get(CSSShorthand.EDGE.ALL.ordinal()));
-  }
-
-  static void updateSparseArray(@NonNull SparseIntArray array, int position, int value) {
-    if (position == CSSShorthand.EDGE.ALL.ordinal()) {
-      array.put(CSSShorthand.EDGE.ALL.ordinal(), value);
-      array.put(CSSShorthand.EDGE.TOP.ordinal(), value);
-      array.put(CSSShorthand.EDGE.LEFT.ordinal(), value);
-      array.put(CSSShorthand.EDGE.RIGHT.ordinal(), value);
-      array.put(CSSShorthand.EDGE.BOTTOM.ordinal(), value);
-    } else {
-      array.put(position, value);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BottomLeftCorner.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BottomLeftCorner.java
deleted file mode 100644
index 40c3d14..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BottomLeftCorner.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.RectF;
-import android.support.annotation.NonNull;
-
-class BottomLeftCorner extends BorderCorner {
-
-  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
-    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 135);
-  }
-
-  @Override
-  protected void prepareOval() {
-    if (hasInnerCorner()) {
-      setOvalLeft(getPostBorderWidth() / 2);
-      setOvalTop(getBorderBox().height() - (2 * getOuterCornerRadius() - getPreBorderWidth() / 2));
-      setOvalRight(2 * getOuterCornerRadius() - getPostBorderWidth() / 2);
-      setOvalBottom(getBorderBox().height() - getPreBorderWidth() / 2);
-    } else {
-      setOvalLeft(getOuterCornerRadius() / 2);
-      setOvalTop(getBorderBox().height() - 1.5f * getOuterCornerRadius());
-      setOvalRight(1.5f * getOuterCornerRadius());
-      setOvalBottom(getBorderBox().height() - getOuterCornerRadius() / 2);
-    }
-  }
-
-  @Override
-  protected void prepareRoundCorner() {
-    if (hasOuterCorner()) {
-      setRoundCornerStartX(getOuterCornerRadius());
-      setRoundCornerStartY(getBorderBox().height() - getPreBorderWidth() / 2);
-
-      setRoundCornerEndX(getPostBorderWidth() / 2);
-      setRoundCornerEndY(getBorderBox().height() - getOuterCornerRadius());
-    } else {
-      final float x = getPostBorderWidth() / 2;
-      final float y = getBorderBox().height() - getPreBorderWidth() / 2;
-
-      setRoundCornerStartX(x);
-      setRoundCornerStartY(y);
-
-      setRoundCornerEndX(x);
-      setRoundCornerEndY(y);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BottomRightCorner.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BottomRightCorner.java
deleted file mode 100644
index 82ef548..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BottomRightCorner.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.RectF;
-import android.support.annotation.NonNull;
-
-class BottomRightCorner extends BorderCorner {
-
-  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
-    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 45);
-  }
-
-  @Override
-  protected void prepareOval() {
-    if (hasInnerCorner()) {
-      setOvalLeft(getBorderBox().width() - (2 * getOuterCornerRadius() - getPreBorderWidth() / 2));
-      setOvalTop(getBorderBox().height() - (2 * getOuterCornerRadius() - getPostBorderWidth() / 2));
-      setOvalRight(getBorderBox().width() - (getPreBorderWidth() / 2));
-      setOvalBottom(getBorderBox().height() - (getPostBorderWidth() / 2));
-    } else {
-      setOvalLeft(getBorderBox().width() - 1.5f * getOuterCornerRadius());
-      setOvalTop(getBorderBox().height() - 1.5f * getOuterCornerRadius());
-      setOvalRight(getBorderBox().width() - getOuterCornerRadius() / 2);
-      setOvalBottom(getBorderBox().height() - getOuterCornerRadius() / 2);
-    }
-  }
-
-  @Override
-  protected void prepareRoundCorner() {
-    if (hasOuterCorner()) {
-      setRoundCornerStartX(getBorderBox().width() - getPreBorderWidth() / 2);
-      setRoundCornerStartY(getBorderBox().height() - getOuterCornerRadius());
-
-      setRoundCornerEndX(getBorderBox().width() - getOuterCornerRadius());
-      setRoundCornerEndY(getBorderBox().height() - getPostBorderWidth() / 2);
-    } else {
-      final float x = getBorderBox().width() - getPreBorderWidth() / 2;
-      final float y = getBorderBox().height() - getPostBorderWidth() / 2;
-
-      setRoundCornerStartX(x);
-      setRoundCornerStartY(y);
-
-      setRoundCornerEndX(x);
-      setRoundCornerEndY(y);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/TopLeftCorner.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/TopLeftCorner.java
deleted file mode 100644
index 42c9cb2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/TopLeftCorner.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.RectF;
-import android.support.annotation.NonNull;
-
-class TopLeftCorner extends BorderCorner {
-
-  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
-    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 225);
-  }
-
-  @Override
-  protected void prepareOval() {
-    if (hasInnerCorner()) {
-      setOvalLeft(getPreBorderWidth() / 2);
-      setOvalTop(getPostBorderWidth() / 2);
-      setOvalRight(2 * getOuterCornerRadius() - getPreBorderWidth() / 2);
-      setOvalBottom(2 * getOuterCornerRadius() - getPostBorderWidth() / 2);
-    } else {
-      setOvalLeft(getOuterCornerRadius() / 2);
-      setOvalTop(getOuterCornerRadius() / 2);
-      setOvalRight(getOuterCornerRadius() * 1.5f);
-      setOvalBottom(getOuterCornerRadius() * 1.5f);
-    }
-  }
-
-  @Override
-  protected void prepareRoundCorner() {
-    if (hasOuterCorner()) {
-      setRoundCornerStartX(getPreBorderWidth() / 2);
-      setRoundCornerStartY(getOuterCornerRadius());
-
-      setRoundCornerEndX(getOuterCornerRadius());
-      setRoundCornerEndY(getPostBorderWidth() / 2);
-    } else {
-      final float x = getPreBorderWidth() / 2;
-      final float y = getPostBorderWidth() / 2;
-
-      setRoundCornerStartX(x);
-      setRoundCornerStartY(y);
-
-      setRoundCornerEndX(x);
-      setRoundCornerEndY(y);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/TopRightCorner.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/TopRightCorner.java
deleted file mode 100644
index 73a0adc..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/TopRightCorner.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.RectF;
-import android.support.annotation.NonNull;
-
-class TopRightCorner extends BorderCorner {
-
-  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
-    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 315);
-  }
-
-  @Override
-  protected void prepareOval() {
-    if (hasInnerCorner()) {
-      setOvalLeft(getBorderBox().width() - (2 * getOuterCornerRadius() - getPostBorderWidth() / 2));
-      setOvalTop(getPreBorderWidth() / 2);
-      setOvalRight(getBorderBox().width() - getPostBorderWidth() / 2);
-      setOvalBottom(2 * getOuterCornerRadius() - getPreBorderWidth() / 2);
-    } else {
-      setOvalLeft(getBorderBox().width() - 1.5f * getOuterCornerRadius());
-      setOvalTop(getOuterCornerRadius() / 2);
-      setOvalRight(getBorderBox().width() - getOuterCornerRadius() / 2);
-      setOvalBottom(getOuterCornerRadius() * 1.5f);
-    }
-  }
-
-  @Override
-  protected void prepareRoundCorner() {
-    if (hasOuterCorner()) {
-      setRoundCornerStartX(getBorderBox().width() - getOuterCornerRadius());
-      setRoundCornerStartY(getPreBorderWidth() / 2);
-
-      setRoundCornerEndX(getBorderBox().width() - getPostBorderWidth() / 2);
-      setRoundCornerEndY(getOuterCornerRadius());
-    } else {
-      final float x = getBorderBox().width() - getPostBorderWidth() / 2;
-      final float y = getPreBorderWidth() / 2;
-
-      setRoundCornerStartX(x);
-      setRoundCornerStartY(y);
-
-      setRoundCornerEndX(x);
-      setRoundCornerEndY(y);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGesture.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGesture.java
deleted file mode 100644
index 6e88d67..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGesture.java
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.gesture;
-
-import static com.taobao.weex.common.Constants.Event.STOP_PROPAGATION;
-import static com.taobao.weex.common.Constants.Event.STOP_PROPAGATION_RAX;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.bridge.EventResult;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.dom.WXEvent;
-import com.taobao.weex.ui.component.Scrollable;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.view.gesture.WXGestureType.GestureInfo;
-import com.taobao.weex.ui.view.gesture.WXGestureType.HighLevelGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureType.LowLevelGesture;
-import com.taobao.weex.utils.WXLogUtils;
-import com.taobao.weex.utils.WXUtils;
-import com.taobao.weex.utils.WXViewUtils;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public class WXGesture extends GestureDetector.SimpleOnGestureListener implements OnTouchListener {
-
-  private final static String TAG = "Gesture";
-  private static final int CUR_EVENT = -1;
-  public static final String START = "start";
-  public static final String MOVE = "move";
-  public static final String END = "end";
-  public static final String UNKNOWN = "unknown";
-  public static final String LEFT = "left";
-  public static final String RIGHT = "right";
-  public static final String UP = "up";
-  public static final String DOWN = "down";
-  private WXComponent component;
-  private GestureDetector mGestureDetector;
-  private Rect globalRect;
-  private Point globalOffset;
-  private Point globalEventOffset;
-  private PointF locEventOffset;
-  private PointF locLeftTop;
-  private long swipeDownTime = -1;
-  private long panDownTime = -1;
-  private WXGestureType mPendingPan = null;//event type to notify when action_up or action_cancel
-  private int mParentOrientation =-1;
-  private boolean mIsPreventMoveEvent = false;
-  private boolean mIsTouchEventConsumed = false; //Reset to false when first touch event, set to true when gesture event fired.
-
-  private boolean requestDisallowInterceptTouchEvent = false;
-
-  private boolean shouldBubbleResult = true;
-  private int     shouldBubbleInterval = 0; //every times try
-  private int     shouldBubbleCallRemainTimes = 0;
-
-  private final List<OnTouchListener> mTouchListeners = new LinkedList<>();
-
-  public WXGesture(WXComponent wxComponent, Context context) {
-    this.component = wxComponent;
-    globalRect = new Rect();
-    globalOffset = new Point();
-    globalEventOffset = new Point();
-    locEventOffset = new PointF();
-    locLeftTop = new PointF();
-    mGestureDetector = new GestureDetector(context, this, new GestureHandler());
-    Scrollable parentScrollable = wxComponent.getParentScroller();
-    if(parentScrollable != null) {
-      mParentOrientation = parentScrollable.getOrientation();
-    }
-    shouldBubbleResult =  WXUtils.getBoolean(wxComponent.getAttrs().get(Constants.Name.SHOULD_STOP_PROPAGATION_INIT_RESULT), true);
-    shouldBubbleInterval = WXUtils.getNumberInt(wxComponent.getAttrs().get(Constants.Name.SHOULD_STOP_PROPAGATION_INTERVAL), 0);
-  }
-
-  private boolean isParentScrollable() {
-    if(component == null) {
-      return true;
-    }
-    Scrollable parentScrollable = component.getParentScroller();
-    return parentScrollable == null || parentScrollable.isScrollable();
-  }
-
-  private boolean hasSameOrientationWithParent(){
-    return (mParentOrientation == Constants.Orientation.HORIZONTAL && component.containsGesture(HighLevelGesture.HORIZONTALPAN))
-            || (mParentOrientation == Constants.Orientation.VERTICAL && component.containsGesture(HighLevelGesture.VERTICALPAN));
-  }
-
-  public void setPreventMoveEvent(boolean preventMoveEvent) {
-    mIsPreventMoveEvent = preventMoveEvent;
-  }
-
-  /**
-   *
-   * @return true if current touch event is already consumed by gesture.
-   * Reset to false when next first touch event, set to true when gesture event fired.
-   */
-  public boolean isTouchEventConsumedByAdvancedGesture(){
-    return mIsTouchEventConsumed;
-  }
-
-
-  /**
-   * stoppropagation
-   * */
-  public static boolean isStopPropagation(String type){
-    return  Constants.Event.STOP_PROPAGATION.equals(type) || Constants.Event.STOP_PROPAGATION_RAX.equals(type);
-  }
-
-  public static boolean hasStopPropagation(WXComponent component){
-    WXEvent event = component.getEvents();
-    if(event == null){
-      return false;
-    }
-    int size = event.size();
-    for (int i=0; i<size; i++) {
-      if(i >= event.size()){
-        break;
-      }
-      String type = event.get(i);
-      if(isStopPropagation(type)){
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * shouldBubbleEvent default true
-   * */
-  private boolean shouldBubbleTouchEvent(MotionEvent event){
-    if(hasStopPropagation(component)){
-      if(shouldBubbleInterval > 0 && shouldBubbleCallRemainTimes > 0){
-        shouldBubbleCallRemainTimes--;
-        return  shouldBubbleResult;
-      }
-      Map<String, Object> eventMap = createFireEventParam(event, CUR_EVENT, null);
-      eventMap.put("type", "touch");
-      if(event.getAction() == MotionEvent.ACTION_DOWN){
-        eventMap.put("action", START);
-      }else if(event.getAction() == MotionEvent.ACTION_CANCEL
-              ||  event.getAction() == MotionEvent.ACTION_UP){
-        eventMap.put("action", END);
-      }else{
-        eventMap.put("action", MOVE);
-      }
-
-      String name = STOP_PROPAGATION;
-      if(!component.getEvents().contains(STOP_PROPAGATION)){
-         name = STOP_PROPAGATION_RAX;
-      }
-      EventResult result = component.fireEventWait(name, eventMap);
-      if(result.isSuccess() && result.getResult() != null){
-        boolean stopPropagation = WXUtils.getBoolean(result.getResult(), !shouldBubbleResult);
-        shouldBubbleResult = !stopPropagation;
-      }
-      shouldBubbleCallRemainTimes = shouldBubbleInterval;
-      return shouldBubbleResult;
-
-    }
-    return  true;
-  }
-
-  @SuppressWarnings("unused")
-  public void addOnTouchListener(OnTouchListener listener) {
-    if(listener != null) {
-      mTouchListeners.add(listener);
-    }
-  }
-
-  @SuppressWarnings("unused")
-  public boolean removeTouchListener(OnTouchListener listener) {
-    if(listener != null) {
-      return mTouchListeners.remove(listener);
-    }
-    return false;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouch(View v, MotionEvent event) {
-    if(requestDisallowInterceptTouchEvent){
-      requestDisallowInterceptTouchEvent = false;
-      return false;
-    }
-    try {
-      boolean result = mGestureDetector.onTouchEvent(event);
-
-      if(mTouchListeners != null && !mTouchListeners.isEmpty()) {
-        for(OnTouchListener listener : mTouchListeners) {
-          result |= listener.onTouch(v, event);
-        }
-      }
-
-      switch (event.getActionMasked()) {
-        case MotionEvent.ACTION_POINTER_DOWN:
-        case MotionEvent.ACTION_DOWN:
-          mIsTouchEventConsumed = false;
-          /**
-           * If component has same scroll orientation with it's parent and it's parent not scrollable
-           * , we should disallow parent in DOWN.
-           */
-          if(hasSameOrientationWithParent() && !isParentScrollable()){
-            ViewParent p;
-            if ((p = component.getRealView().getParent()) != null) {
-              p.requestDisallowInterceptTouchEvent(true);
-            }
-          }
-          result |= handleMotionEvent(LowLevelGesture.ACTION_DOWN, event);
-          break;
-        case MotionEvent.ACTION_MOVE:
-          result |= handleMotionEvent(LowLevelGesture.ACTION_MOVE, event);
-          break;
-        case MotionEvent.ACTION_UP:
-        case MotionEvent.ACTION_POINTER_UP:
-          finishDisallowInterceptTouchEvent(v);
-          result |= handleMotionEvent(LowLevelGesture.ACTION_UP, event);
-          result |= handlePanMotionEvent(event);
-          break;
-        case MotionEvent.ACTION_CANCEL:
-          finishDisallowInterceptTouchEvent(v);
-          result |= handleMotionEvent(LowLevelGesture.ACTION_CANCEL, event);
-          result |= handlePanMotionEvent(event);
-          break;
-      }
-      if(hasStopPropagation(component)){
-        ViewGroup parent = (ViewGroup) v.getParent();
-        boolean requestDisallowInterceptTouchEvent = false;
-        if(parent != null){
-          if(!shouldBubbleTouchEvent(event)){
-            requestDisallowInterceptTouchEvent = true;
-          }
-          parent.requestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
-        }
-        if(component.getParent() != null){
-          component.getParent().requestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
-        }
-        if(mIsTouchEventConsumed && WXUtils.getBoolean(component.getAttrs().get("cancelTouchOnConsume"), false)){//when touch event consumed by one gesture, other component should not consumed
-          event.setAction(MotionEvent.ACTION_CANCEL);
-        }
-      }
-      return result;
-    } catch (Exception e) {
-      WXLogUtils.e("Gesture RunTime Error ", e);
-      return false;
-    }
-  }
-
-  private String getPanEventAction(MotionEvent event) {
-    switch (event.getAction()) {
-      case MotionEvent.ACTION_DOWN:
-        return START;
-      case MotionEvent.ACTION_MOVE:
-        return MOVE;
-      case MotionEvent.ACTION_UP:
-        return END;
-      case MotionEvent.ACTION_CANCEL:
-        return END;
-      default:
-        return UNKNOWN;
-    }
-  }
-
-  private void finishDisallowInterceptTouchEvent(View v){
-    if(v.getParent() != null){
-      v.getParent().requestDisallowInterceptTouchEvent(false);
-    }
-  }
-
-  private boolean handlePanMotionEvent(MotionEvent motionEvent) {
-    if (mPendingPan == null) {
-      return false;
-    }
-    String state = null;
-    if (mPendingPan == HighLevelGesture.HORIZONTALPAN || mPendingPan == HighLevelGesture.VERTICALPAN) {
-      state = getPanEventAction(motionEvent);
-
-    }
-
-    if (component.containsGesture(mPendingPan)) {
-      if(mIsPreventMoveEvent && MOVE.equals(state)){
-        return true;
-      }
-      List<Map<String, Object>> list = createMultipleFireEventParam(motionEvent, state);
-      for (Map<String, Object> map : list) {
-        component.fireEvent(mPendingPan.toString(), map);
-      }
-      //action is finish, clean pending pan
-      if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
-        mPendingPan = null;
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  /**
-   *
-   * @param WXGestureType possible low-level gesture, defined in {@link com.taobao.weex.common.Constants.Event}
-   * @param motionEvent motionEvent, which contains all pointers event in a period of time
-   * @return true if this event is handled, otherwise false.
-   */
-  private boolean handleMotionEvent(WXGestureType WXGestureType, MotionEvent motionEvent) {
-    if (component.containsGesture(WXGestureType)) {
-      List<Map<String, Object>> list = createMultipleFireEventParam(motionEvent, null);
-      for (Map<String, Object> map : list) {
-        component.fireEvent(WXGestureType.toString(), map);
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  /**
-   * Create a list of event for {@link com.taobao.weex.WXSDKInstance#fireEvent(String, String, Map, Map)}.
-   * As there is a batch mechanism in MotionEvent, so this method returns a list.
-   * @param motionEvent motionEvent, which contains all pointers event in a period of time
-   * @return List of Map, which contains touch object.
-   */
-  private List<Map<String, Object>> createMultipleFireEventParam(MotionEvent motionEvent,String state) {
-    List<Map<String, Object>> list = new ArrayList<>(motionEvent.getHistorySize() + 1);
-    //list.addAll(getHistoricalEvents(motionEvent));
-    list.add(createFireEventParam(motionEvent, CUR_EVENT, state));
-    return list;
-  }
-
-  /**
-   * Get historical event. This is only applied to {@link MotionEvent#ACTION_MOVE}.
-   * For other types of motionEvent, historical event is meaningless.
-   * @param motionEvent motionEvent, which contains all pointers event in a period of time
-   * @return If motionEvent.getActionMasked()!=MotionEvent.ACTION_MOVE,
-   * this method will return an empty list.
-   * Otherwise this method will return the historical motionEvent, which may also be empty.
-   */
-  private List<Map<String, Object>> getHistoricalEvents(MotionEvent motionEvent) {
-    List<Map<String, Object>> list = new ArrayList<>(motionEvent.getHistorySize());
-    if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
-      Map<String, Object> param;
-      for (int i = 0; i < motionEvent.getHistorySize(); i++) {
-        param = createFireEventParam(motionEvent, i,null);
-        list.add(param);
-      }
-    }
-    return list;
-  }
-
-  /**
-   * Create a map represented touch event at a certain moment.
-   * @param motionEvent motionEvent, which contains all pointers event in a period of time
-   * @param pos index used to retrieve a certain moment in a period of time.
-   * @return touchEvent
-   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent">touchEvent</a>
-   */
-  private Map<String, Object> createFireEventParam(MotionEvent motionEvent, int pos, String state) {
-    JSONArray jsonArray = new JSONArray(motionEvent.getPointerCount());
-    if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
-      for (int i = 0; i < motionEvent.getPointerCount(); i++) {
-        jsonArray.add(createJSONObject(motionEvent, pos, i));
-      }
-    } else if (isPointerNumChanged(motionEvent)) {
-      int pointerIndex = motionEvent.getActionIndex();
-      jsonArray.add(createJSONObject(motionEvent, CUR_EVENT, pointerIndex));
-    }
-    Map<String, Object> map = new HashMap<>();
-    map.put(GestureInfo.HISTORICAL_XY, jsonArray);
-    if (state != null) {
-      map.put(GestureInfo.STATE, state);
-    }
-    return map;
-  }
-
-  /**
-   * Tell whether the number of motion event's pointer changed.
-   * @param event the current motion event
-   * @return true for number of motion event's pointer changed, otherwise false.
-   */
-  private boolean isPointerNumChanged(MotionEvent event) {
-    return event.getActionMasked() == MotionEvent.ACTION_DOWN ||
-            event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN ||
-            event.getActionMasked() == MotionEvent.ACTION_UP ||
-            event.getActionMasked() == MotionEvent.ACTION_POINTER_UP ||
-            event.getActionMasked() == MotionEvent.ACTION_CANCEL;
-  }
-
-  /**
-   * Tell whether component contains pan gesture
-   * @return true for contains pan gesture, otherwise false.
-   */
-  private boolean containsSimplePan() {
-    return component.containsGesture(HighLevelGesture.PAN_START) ||
-            component.containsGesture(HighLevelGesture.PAN_MOVE) ||
-            component.containsGesture(HighLevelGesture.PAN_END);
-  }
-
-  /**
-   * Create a touchObject for a pointer at a certain moment.
-   * @param motionEvent motionEvent, which contains all pointers event in a period of time
-   * @param pos index used to retrieve a certain moment in a period of time.
-   * @param pointerIndex pointerIndex
-   * @return JSONObject represent a touch event
-   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch">touch</a>
-   */
-  private JSONObject createJSONObject(MotionEvent motionEvent, int pos, int pointerIndex) {
-    PointF screenXY, pageXY;
-    if (pos == CUR_EVENT) {
-      pageXY = getEventLocInPageCoordinate(motionEvent, pointerIndex);
-      screenXY = getEventLocInScreenCoordinate(motionEvent, pointerIndex);
-    } else {
-      pageXY = getEventLocInPageCoordinate(motionEvent, pointerIndex, pos);
-      screenXY = getEventLocInScreenCoordinate(motionEvent, pointerIndex, pos);
-    }
-    JSONObject map = createJSONObject(screenXY, pageXY, (float) motionEvent.getPointerId(pointerIndex));
-    float force = motionEvent.getPressure();
-    if(force > 0 && force < 1) {
-      map.put("force", motionEvent.getPressure());
-    }
-    return map;
-  }
-
-  /**
-   * Create a touchObject for a pointer at a certain moment.
-   * @param screenXY the point of event happened in screen coordinate
-   * @param pageXY the point of event happened in page coorindate
-   * @param pointerId pointerIndex pointerIndex
-   * @return JSONObject represent a touch event
-   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch">touch</a>
-   */
-  @NonNull
-  private JSONObject createJSONObject(PointF screenXY, PointF pageXY, float pointerId) {
-    JSONObject jsonObject = new JSONObject();
-    jsonObject.put(GestureInfo.PAGE_X, pageXY.x);
-    jsonObject.put(GestureInfo.PAGE_Y, pageXY.y);
-    jsonObject.put(GestureInfo.SCREEN_X, screenXY.x);
-    jsonObject.put(GestureInfo.SCREEN_Y, screenXY.y);
-    jsonObject.put(GestureInfo.POINTER_ID, pointerId);
-    return jsonObject;
-  }
-
-  /**
-   * @see {@link #getEventLocInScreenCoordinate(MotionEvent, int, int)}
-   */
-  private PointF getEventLocInScreenCoordinate(MotionEvent motionEvent, int pointerIndex) {
-    return getEventLocInScreenCoordinate(motionEvent, pointerIndex, CUR_EVENT);
-  }
-
-  /**
-   * Get event location in Screen's coordinate, e.g. root(global) coordinate.
-   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/screenX">screenX</a>
-   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/screenY">screenY</a>
-   * @param motionEvent the original motionEvent
-   * @param pointerIndex pointerIndex
-   * @param position if motionEvent.getHistoricalSize()!=0, the is the index of historical event,
-   *                 otherwise this is {@link #CUR_EVENT} which indicates historicalSize is zero
-   * @return the eventLocation in screen's coordinate
-   */
-  private PointF getEventLocInScreenCoordinate(MotionEvent motionEvent, int pointerIndex, int position) {
-    float eventX, eventY;
-    if (position == CUR_EVENT) {
-      eventX = motionEvent.getX(pointerIndex);
-      eventY = motionEvent.getY(pointerIndex);
-    } else {
-      eventX = motionEvent.getHistoricalX(pointerIndex, position);
-      eventY = motionEvent.getHistoricalY(pointerIndex, position);
-    }
-    return getEventLocInScreenCoordinate(eventX, eventY);
-  }
-
-  /**
-   * Get event location in Screen's coordinate, e.g. root(global) coordinate.
-   * @param eventX {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
-   * @param eventY {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
-   * @return the eventLocation in screen's coordinate
-   * @see {@link #getEventLocInScreenCoordinate(MotionEvent, int, int)}
-   */
-  @NonNull
-  private PointF getEventLocInScreenCoordinate(float eventX, float eventY) {
-    globalRect.set(0, 0, 0, 0);
-    globalOffset.set(0, 0);
-    globalEventOffset.set((int) eventX, (int) eventY);
-    component.getRealView().getGlobalVisibleRect(globalRect, globalOffset);
-    globalEventOffset.offset(globalOffset.x, globalOffset.y);
-    return new PointF(WXViewUtils.getWebPxByWidth(globalEventOffset.x,component.getInstance().getInstanceViewPortWidth()),
-            WXViewUtils.getWebPxByWidth(globalEventOffset.y,component.getInstance().getInstanceViewPortWidth()));
-  }
-
-  /**
-   * @see {@link #getEventLocInPageCoordinate(MotionEvent, int, int)}
-   */
-  private PointF getEventLocInPageCoordinate(MotionEvent motionEvent, int pointerIndex) {
-    return getEventLocInPageCoordinate(motionEvent, pointerIndex, CUR_EVENT);
-  }
-
-  /**
-   * Get event's location in Document's (Page) coordinate.
-   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/pageX">pageX</a>
-   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/pageY">pageY</a>
-   * @param motionEvent the original motionEvent
-   * @param pointerIndex pointerIndex
-   * @param position if motionEvent.getHistoricalSize()!=0, the is the index of historical event,
-   *                 otherwise this is {@link #CUR_EVENT} which indicates historicalSize is zero
-   * @return the event location in page's coordinate.
-   */
-  private PointF getEventLocInPageCoordinate(MotionEvent motionEvent, int pointerIndex, int position) {
-    float eventX, eventY;
-    if (position == CUR_EVENT) {
-      eventX = motionEvent.getX(pointerIndex);
-      eventY = motionEvent.getY(pointerIndex);
-    } else {
-      eventX = motionEvent.getHistoricalX(pointerIndex, position);
-      eventY = motionEvent.getHistoricalY(pointerIndex, position);
-    }
-    return getEventLocInPageCoordinate(eventX, eventY);
-  }
-
-  /**
-   * Get event's location in Document's (Page) coordinate.
-   * @param eventX {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
-   * @param eventY {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
-   * @return the event location in page's coordinate.
-   * @see {@link #getEventLocInPageCoordinate(MotionEvent, int, int)}
-   */
-  @NonNull
-  private PointF getEventLocInPageCoordinate(float eventX, float eventY) {
-    locEventOffset.set(eventX, eventY);
-    locLeftTop.set(0, 0);
-    component.computeVisiblePointInViewCoordinate(locLeftTop);
-    locEventOffset.offset(locLeftTop.x, locLeftTop.y);
-    return new PointF(WXViewUtils.getWebPxByWidth(locEventOffset.x,component.getInstance().getInstanceViewPortWidth()),
-            WXViewUtils.getWebPxByWidth(locEventOffset.y,component.getInstance().getInstanceViewPortWidth()));
-  }
-
-  private static class GestureHandler extends android.os.Handler {
-
-    public GestureHandler() {
-      super(Looper.getMainLooper());
-    }
-  }
-
-
-  /***************** OnGestureListener ****************/
-
-  @Override
-  public void onLongPress(MotionEvent e) {
-    if (component.containsGesture(HighLevelGesture.LONG_PRESS)) {
-      List<Map<String, Object>> list = createMultipleFireEventParam(e,null);
-      component.getInstance().fireEvent(
-              component.getRef(),
-              HighLevelGesture.LONG_PRESS.toString(),
-              list.get(list.size() - 1));
-      mIsTouchEventConsumed = true;
-    }
-  }
-
-  /**
-   * Gesture priority:horizontalPan & verticalPan > pan > swipe
-   */
-  @Override
-  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-    boolean result = false;
-    if (e1 == null || e2 == null) {
-      return false;
-    }
-    float dx = Math.abs(e2.getX() - e1.getX());
-    float dy = Math.abs(e2.getY() - e1.getY());
-    WXGestureType possiblePan;
-    if (dx > dy) {
-      possiblePan = HighLevelGesture.HORIZONTALPAN;
-    } else {
-      possiblePan = HighLevelGesture.VERTICALPAN;
-    }
-    if (mPendingPan == HighLevelGesture.HORIZONTALPAN || mPendingPan == HighLevelGesture.VERTICALPAN) {
-      //already during directional-pan
-      result = handlePanMotionEvent(e2);
-    } else if (component.containsGesture(possiblePan)) {
-      ViewParent p;
-      if ((p = component.getRealView().getParent()) != null) {
-        p.requestDisallowInterceptTouchEvent(true);
-      }
-      if (mPendingPan != null) {
-        handleMotionEvent(mPendingPan, e2);//finish pan if exist
-      }
-      mPendingPan = possiblePan;
-      component.fireEvent(possiblePan.toString(), createFireEventParam(e2, CUR_EVENT, START));
-
-      result = true;
-    } else if (containsSimplePan()) {
-      if (panDownTime != e1.getEventTime()) {
-        panDownTime = e1.getEventTime();
-        mPendingPan = HighLevelGesture.PAN_END;
-        component.fireEvent(HighLevelGesture.PAN_START.toString(),
-                createFireEventParam(e1, CUR_EVENT, null));
-      } else {
-        component.fireEvent(HighLevelGesture.PAN_MOVE.toString(),
-                createFireEventParam(e2, CUR_EVENT, null));
-      }
-      result = true;
-    } else if (component.containsGesture(HighLevelGesture.SWIPE)) {
-      if (swipeDownTime != e1.getEventTime()) {
-        swipeDownTime = e1.getEventTime();
-        List<Map<String, Object>> list = createMultipleFireEventParam(e2, null);
-        Map<String, Object> param = list.get(list.size() - 1);
-        if (Math.abs(distanceX) > Math.abs(distanceY)) {
-          param.put(GestureInfo.DIRECTION, distanceX > 0 ? LEFT : RIGHT);
-        } else {
-          param.put(GestureInfo.DIRECTION, distanceY > 0 ? UP : DOWN);
-        }
-        component.getInstance().fireEvent(component.getRef(),
-                HighLevelGesture.SWIPE.toString(), param);
-        result = true;
-      }
-    }
-    mIsTouchEventConsumed = mIsTouchEventConsumed || result;
-    return result;
-  }
-
-  @Override
-  public boolean onDown(MotionEvent e) {
-    return true;
-  }
-
-  public boolean isRequestDisallowInterceptTouchEvent() {
-    return requestDisallowInterceptTouchEvent;
-  }
-
-  public void setRequestDisallowInterceptTouchEvent(boolean requestDisallowInterceptTouchEvent) {
-    this.requestDisallowInterceptTouchEvent = requestDisallowInterceptTouchEvent;
-  }
-
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGestureObservable.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGestureObservable.java
deleted file mode 100644
index e568793..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGestureObservable.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.gesture;
-
-import android.support.annotation.Nullable;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.taobao.weex.ui.view.WXFrameLayout;
-
-/**
- * Views that want to receive Gesture Event must implement this interface. Besides,
- * those view must override their {@link android.view.View#onTouchEvent(MotionEvent)}
- * and add method invocation to {@link WXGesture#onTouch(View, MotionEvent)}.
- * Refer to {@link WXFrameLayout#onTouchEvent(MotionEvent)} for more info.
- *
- */
-public interface WXGestureObservable {
-
-  /**
-   * Register a {@link WXGesture} for corresponding view.
-   * @param wxGesture The Gesture to register, null for unregister.
-   */
-  void registerGestureListener(@Nullable WXGesture wxGesture);
-
-  /**
-   * Get gesture listener for corresponding view.
-   *
-   * @return the gesture listener has register before
-   *
-   * */
-  WXGesture getGestureListener();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGestureType.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGestureType.java
deleted file mode 100644
index 807daac..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/gesture/WXGestureType.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.gesture;
-
-public interface WXGestureType {
-
-  enum LowLevelGesture implements WXGestureType {
-    ACTION_DOWN("touchstart"),
-    ACTION_MOVE("touchmove"),
-    ACTION_UP("touchend"),
-    ACTION_CANCEL("touchcancel");
-    private String description;
-
-    LowLevelGesture(String description) {
-      this.description = description;
-    }
-
-    @Override
-    public String toString() {
-      return description;
-    }
-  }
-
-  enum HighLevelGesture implements WXGestureType {
-    SWIPE("swipe"),
-    LONG_PRESS("longpress"),
-    PAN_START("panstart"),
-    PAN_MOVE("panmove"),
-    PAN_END("panend"),
-    HORIZONTALPAN("horizontalpan"),
-    VERTICALPAN("verticalpan");
-    private String description;
-
-    HighLevelGesture(String description) {
-      this.description = description;
-    }
-
-    @Override
-    public String toString() {
-      return description;
-    }
-  }
-
-  class GestureInfo {
-
-    public static final String HISTORICAL_XY = "changedTouches";
-    public static final String PAGE_X = "pageX";
-    public static final String PAGE_Y = "pageY";
-    public static final String SCREEN_X = "screenX";
-    public static final String SCREEN_Y = "screenY";
-    public static final String POINTER_ID = "identifier";
-    public static final String DIRECTION = "direction";
-    public static final String STATE = "state";
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/ExtendedLinearLayoutManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/ExtendedLinearLayoutManager.java
deleted file mode 100644
index bdb5f91..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/ExtendedLinearLayoutManager.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview;
-
-import android.content.Context;
-import android.graphics.PointF;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.LinearSmoothScroller;
-import android.support.v7.widget.RecyclerView;
-
-/**
- * Created by moxun on 17/2/16.
- */
-
-public class ExtendedLinearLayoutManager extends LinearLayoutManager{
-
-    private RecyclerView.SmoothScroller smoothScroller;
-
-
-    private OnSmoothScrollEndListener onScrollEndListener;
-
-    public ExtendedLinearLayoutManager(Context context) {
-        super(context, VERTICAL, false);
-    }
-
-    public ExtendedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
-        super(context, orientation, reverseLayout);
-    }
-
-    @Override
-    public boolean supportsPredictiveItemAnimations() {
-        return false;
-    }
-
-    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-        try {
-            super.onLayoutChildren(recycler, state);
-        } catch (IndexOutOfBoundsException e) {
-            e.printStackTrace();
-
-        }
-    }
-
-    @Override
-    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
-        try {
-            return super.scrollVerticallyBy(dy, recycler, state);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return 0;
-    }
-
-
-    @Override
-    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
-                                       int position) {
-        if (smoothScroller == null) {
-            smoothScroller = new ExtendedLinearLayoutManager.TopSnappedSmoothScroller(recyclerView.getContext());
-        }
-        smoothScroller.setTargetPosition(position);
-        startSmoothScroll(smoothScroller);
-    }
-
-    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
-        public TopSnappedSmoothScroller(Context context) {
-            super(context);
-
-        }
-
-        @Override
-        public PointF computeScrollVectorForPosition(int targetPosition) {
-            return ExtendedLinearLayoutManager.this
-                    .computeScrollVectorForPosition(targetPosition);
-        }
-
-        @Override
-        protected int getVerticalSnapPreference() {
-            return SNAP_TO_START;
-        }
-
-        @Override
-        protected void onStop() {
-            super.onStop();
-            if(onScrollEndListener != null){
-                onScrollEndListener.onStop();
-                onScrollEndListener = null;
-            }
-        }
-    }
-
-    public void setOnScrollEndListener(OnSmoothScrollEndListener onScrollEndListener) {
-        this.onScrollEndListener = onScrollEndListener;
-    }
-
-    public interface OnSmoothScrollEndListener {
-        void  onStop();
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/ExtendedStaggeredGridLayoutManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/ExtendedStaggeredGridLayoutManager.java
deleted file mode 100644
index ee27ab2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/ExtendedStaggeredGridLayoutManager.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview;
-
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.utils.WXLogUtils;
-
-/**
- * Created by zhengshihan on 2017/5/5.
- */
-
-public class ExtendedStaggeredGridLayoutManager extends StaggeredGridLayoutManager{
-
-  public ExtendedStaggeredGridLayoutManager(int spanCount, int orientation) {
-    super(spanCount, orientation);
-  }
-
-  @Override
-  public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
-    if(positionStart ==-1){
-      WXLogUtils.e("ExtendedStaggeredGridLayoutManager: onItemsRemoved  Error Invalid Index : positionStart :"+positionStart +"  itemCount:"+ itemCount);
-      return ;
-    }else {
-      if(WXEnvironment.isApkDebugable()){
-        WXLogUtils.e("ExtendedStaggeredGridLayoutManager: onItemsRemoved  positionStart :"+positionStart+"  itemCount:"+ itemCount);
-      }
-    }
-    super.onItemsRemoved(recyclerView, positionStart, itemCount);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/WXRecyclerView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/WXRecyclerView.java
deleted file mode 100644
index 3f0d990..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/WXRecyclerView.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.OrientationHelper;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.view.MotionEvent;
-
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-
-public class WXRecyclerView extends RecyclerView implements WXGestureObservable {
-
-  public static final int TYPE_LINEAR_LAYOUT = 1;
-  public static final int TYPE_GRID_LAYOUT = 2;
-  public static final int TYPE_STAGGERED_GRID_LAYOUT = 3;
-  private WXGesture mGesture;
-  private boolean scrollable = true;
-  private boolean hasTouch = false;
-
-
-  public WXRecyclerView(Context context) {
-    super(context);
-  }
-
-  public boolean isScrollable() {
-    return scrollable;
-  }
-
-  public void setScrollable(boolean scrollable) {
-    this.scrollable = scrollable;
-  }
-
-  public void initView(Context context, int type,int orientation) {
-    initView(context,type, Constants.Value.COLUMN_COUNT_NORMAL,Constants.Value.COLUMN_GAP_NORMAL,orientation);
-  }
-
-
-  /**
-   *
-   * @param context
-   * @param type
-   * @param orientation should be {@link OrientationHelper#HORIZONTAL} or {@link OrientationHelper#VERTICAL}
-   */
-  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-  public void initView(Context context, int type, int columnCount, float columnGap, int orientation) {
-    if (type == TYPE_GRID_LAYOUT) {
-      setLayoutManager(new GridLayoutManager(context, columnCount,orientation,false));
-    } else if (type == TYPE_STAGGERED_GRID_LAYOUT) {
-      setLayoutManager(new ExtendedStaggeredGridLayoutManager(columnCount, orientation));
-    } else if (type == TYPE_LINEAR_LAYOUT) {
-      setLayoutManager(new ExtendedLinearLayoutManager(context,orientation,false));
-    }
-  }
-
-  @Override
-  public void registerGestureListener(@Nullable WXGesture wxGesture) {
-    mGesture = wxGesture;
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return mGesture;
-  }
-
-  @SuppressLint("ClickableViewAccessibility")
-  @Override
-  public boolean onTouchEvent(MotionEvent event) {
-    if(!scrollable) {
-      return true;
-    }
-    return super.onTouchEvent(event);
-  }
-
-  @Override
-  public boolean dispatchTouchEvent(MotionEvent event) {
-    hasTouch = true;
-    boolean result = super.dispatchTouchEvent(event);
-    if (mGesture != null) {
-      result |= mGesture.onTouch(this, event);
-    }
-    return result;
-  }
-
-  public void scrollTo(boolean smooth, int position, final  int offset, final int orientation){
-    if (!smooth) {
-      RecyclerView.LayoutManager layoutManager = getLayoutManager();
-      if (layoutManager instanceof LinearLayoutManager) {
-        //GridLayoutManager is also instance of LinearLayoutManager
-        ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, -offset);
-      } else if (layoutManager instanceof StaggeredGridLayoutManager) {
-        ((StaggeredGridLayoutManager) layoutManager).scrollToPositionWithOffset(position, -offset);
-      }
-      //Any else?
-    } else {
-      smoothScrollToPosition(position);
-      if (offset != 0) {
-        setOnSmoothScrollEndListener(new ExtendedLinearLayoutManager.OnSmoothScrollEndListener() {
-          @Override
-          public void onStop() {
-            post(WXThread.secure(new Runnable() {
-              @Override
-              public void run() {
-                if (orientation == Constants.Orientation.VERTICAL) {
-                  smoothScrollBy(0, offset);
-                } else {
-                  smoothScrollBy(offset, 0);
-                }
-              }
-            }));
-          }
-        });
-      }
-    }
-  }
-
-  public void setOnSmoothScrollEndListener(final ExtendedLinearLayoutManager.OnSmoothScrollEndListener onSmoothScrollEndListener){
-    addOnScrollListener(new RecyclerView.OnScrollListener() {
-      @Override
-      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
-          recyclerView.removeOnScrollListener(this);
-          if(onSmoothScrollEndListener != null){
-            onSmoothScrollEndListener.onStop();
-          }
-        }
-      }
-    });
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/IOnLoadMoreListener.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/IOnLoadMoreListener.java
deleted file mode 100644
index e703149..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/IOnLoadMoreListener.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview.adapter;
-
-
-public interface IOnLoadMoreListener {
-
-  void onLoadMore(int offScreenY);
-  void notifyAppearStateChange(int firstVisible, int lastVisible, int directionX, int directionY);
-  void onBeforeScroll(int dx, int dy);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/IRecyclerAdapterListener.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/IRecyclerAdapterListener.java
deleted file mode 100644
index 36094f2..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/IRecyclerAdapterListener.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview.adapter;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.ViewGroup;
-
-/**
- * Listener for recyclerView event
- */
-public interface IRecyclerAdapterListener<T extends RecyclerView.ViewHolder> {
-
-  void onViewRecycled(T holder);
-
-  void onBindViewHolder(T holder, int position);
-
-  T onCreateViewHolder(ViewGroup parent, int viewType);
-
-  int getItemViewType(int position);
-
-  int getItemCount();
-
-  boolean onFailedToRecycleView(T holder);
-
-  long getItemId(int position);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/ListBaseViewHolder.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/ListBaseViewHolder.java
deleted file mode 100644
index 3c332da..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/ListBaseViewHolder.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview.adapter;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXHeader;
-
-import java.lang.ref.WeakReference;
-
-
-/**
- * There are bi-directional association between ViewHolder and View.
- * This is accomplished by weak-reference and final field from ViewHolder to View.
- * From View to ViewHolder, this is done by set {@link android.view.ViewGroup.LayoutParams} to View.
- */
-public class ListBaseViewHolder extends RecyclerView.ViewHolder {
-  private int mViewType;
-  private boolean isRecycled;
-  private WeakReference<WXComponent> mComponent;
-
-  public ListBaseViewHolder(WXComponent component, int viewType) {
-    super(component.getHostView());
-    mViewType = viewType;
-    mComponent = new WeakReference(component);
-    // This tag is used to determine whether bind / rebind data is needed.
-    // It should be false When component can not be recycled Which means
-    // no need to bind / rebind data.
-    isRecycled = component.canRecycled();
-  }
-
-  public ListBaseViewHolder(WXComponent component, int viewType, boolean forceBindData) {
-    this(component, viewType);
-    isRecycled = isRecycled || forceBindData;
-  }
-
-  public ListBaseViewHolder(View view, int viewType) {
-    super(view);
-    mViewType = viewType;
-  }
-
-  public boolean isRecycled() {
-    return isRecycled;
-  }
-
-  public void recycled() {
-    if (mComponent != null && mComponent.get() != null) {
-      mComponent.get().recycled();
-      isRecycled = true;
-
-    }
-  }
-
-  public void bindData(WXComponent component) {
-    if (mComponent != null && mComponent.get() != null) {
-      mComponent.get().bindData(component);
-      isRecycled = false;
-    }
-  }
-    
-  public boolean isFullSpan() {
-    return mComponent != null && mComponent.get() instanceof WXHeader;
-  }
-
-  public boolean canRecycled() {
-    if (mComponent != null && mComponent.get() != null) {
-      return mComponent.get().canRecycled();
-    }
-    return true;
-  }
-
-  public View getView() {
-    return itemView;
-  }
-
-  public int getViewType() {
-    return mViewType;
-  }
-
-  public void setComponentUsing(boolean using) {
-    if (mComponent != null && mComponent.get() != null)
-      mComponent.get().setUsing(using);
-  }
-
-  public WXComponent getComponent() {
-    return mComponent != null ? mComponent.get() : null;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/RecyclerViewBaseAdapter.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/RecyclerViewBaseAdapter.java
deleted file mode 100644
index b7ba22d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/RecyclerViewBaseAdapter.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview.adapter;
-
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.view.ViewGroup;
-
-
-/**
- * Adapter for recyclerView
- */
-public class RecyclerViewBaseAdapter<T extends ListBaseViewHolder> extends RecyclerView.Adapter<T> {
-
-  private IRecyclerAdapterListener iRecyclerAdapterListener;
-
-  public RecyclerViewBaseAdapter(IRecyclerAdapterListener Listener) {
-    this.iRecyclerAdapterListener = Listener;
-  }
-
-  @Override
-  public T onCreateViewHolder(ViewGroup parent, int viewType) {
-    if (iRecyclerAdapterListener != null) {
-      return (T) iRecyclerAdapterListener.onCreateViewHolder(parent, viewType);
-    }
-
-    return null;
-  }
-
-  @Override
-  public void onViewAttachedToWindow(T holder) {
-    super.onViewAttachedToWindow(holder);
-    if( holder !=null && holder.isFullSpan()){
-      ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-      if(lp != null
-              && lp instanceof StaggeredGridLayoutManager.LayoutParams
-              ) {
-        StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
-        p.setFullSpan(true);
-      }
-    }
-  }
-
-  @Override
-  public void onViewDetachedFromWindow(T holder) {
-    super.onViewDetachedFromWindow(holder);
-    if (holder != null)
-      holder.setComponentUsing(false);
-  }
-
-  @Override
-  public void onBindViewHolder(T viewHolder, int i) {
-    if (iRecyclerAdapterListener != null) {
-      iRecyclerAdapterListener.onBindViewHolder(viewHolder, i);
-    }
-  }
-
-  @Override
-  public int getItemViewType(int position) {
-    if (iRecyclerAdapterListener != null) {
-      return iRecyclerAdapterListener.getItemViewType(position);
-    }
-    return position;
-  }
-
-  @Override
-  public long getItemId(int position) {
-    return iRecyclerAdapterListener.getItemId(position);
-  }
-
-  @Override
-  public int getItemCount() {
-    if (iRecyclerAdapterListener != null) {
-      return iRecyclerAdapterListener.getItemCount();
-    }
-    return 0;
-  }
-
-  @Override
-  public void onViewRecycled(T holder) {
-    if (iRecyclerAdapterListener != null) {
-      iRecyclerAdapterListener.onViewRecycled(holder);
-    }
-    super.onViewRecycled(holder);
-  }
-
-  @Override
-  public boolean onFailedToRecycleView(T holder) {
-    if (iRecyclerAdapterListener != null) {
-      return iRecyclerAdapterListener.onFailedToRecycleView(holder);
-    }
-    return super.onFailedToRecycleView(holder);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/TransformItemDecoration.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/TransformItemDecoration.java
deleted file mode 100644
index 415c7d5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/TransformItemDecoration.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview.adapter;
-
-import android.graphics.Canvas;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-public class TransformItemDecoration extends RecyclerView.ItemDecoration{
-  boolean mIsVertical = true;
-  float mAlpha = -1f;
-  int mXTranslate = 0;
-  int mYTranslate = 0;
-  int mRotation = 0;
-  float mScaleX = 0;
-  float mScaleY  = 0;
-
-  public TransformItemDecoration(boolean isVertical,float alpha,int translateX,int translateY,int rotation,float scaleX,float scaleY){
-    this.mIsVertical = isVertical;
-    this.mAlpha = alpha;
-    this.mXTranslate = translateX;
-    this.mYTranslate = translateY;
-    this.mRotation = rotation;
-    this.mScaleX = scaleX;
-    this.mScaleY = scaleY;
-  }
-
-
-  @Override
-  public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
-    super.onDrawOver(c, parent, state);
-    int width = parent.getWidth();
-    int height = parent.getHeight();
-    for (int i = 0,count=parent.getChildCount(); i < count; i++) {
-      updateItem(parent.getChildAt(i),width,height);
-    }
-  }
-
-  private void updateItem(View child, int width, int height) {
-    int size,childCenter,containerSize;
-    if (mIsVertical) {
-      containerSize = height;
-      size = child.getHeight();
-      childCenter = child.getTop() + size / 2;
-    } else {
-      containerSize = width;
-      size = child.getWidth();
-      childCenter = child.getLeft() + size / 2;
-    }
-
-    final int actionDistance = (containerSize + size) / 2;
-    final float effectsAmount = Math.min(1.0f, Math.max(-1.0f, (1.0f / actionDistance) * (childCenter - containerSize/2)));
-
-
-    if(mAlpha>0){
-      child.setAlpha(1-mAlpha*Math.abs(effectsAmount));
-    }
-
-    if(mScaleX>0||mScaleY>0){
-      child.setScaleX(1-mScaleX*Math.abs(effectsAmount));
-      child.setScaleY(1-mScaleY*Math.abs(effectsAmount));
-    }
-
-    if(mRotation!=0){
-      child.setRotation(mRotation * effectsAmount);
-    }
-
-    if(mXTranslate!=0){
-      child.setTranslationX(mXTranslate * Math.abs( effectsAmount));
-    }
-
-    if(mYTranslate!=0){
-      child.setTranslationY(mYTranslate * Math.abs( effectsAmount));
-    }
-
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/WXRecyclerViewOnScrollListener.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/WXRecyclerViewOnScrollListener.java
deleted file mode 100644
index 694c8b5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/adapter/WXRecyclerViewOnScrollListener.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.listview.adapter;
-
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.ref.WeakReference;
-
-
-/**
- * Listener for scroll event of recyclerView
- */
-public class WXRecyclerViewOnScrollListener extends RecyclerView.OnScrollListener {
-
-  /**
-   * type of layoutManager
-   */
-  protected LAYOUT_MANAGER_TYPE layoutManagerType;
-
-  /**
-   * The last position
-   */
-  private int[] mLastPositions;
-  /**
-   * The first position
-   */
-  private int[] mFirstPositions;
-
-
-  /**
-   * The location of last visible item
-   */
-  private int mLastVisibleItemPosition;
-
-  /**
-   * The location of last visible item
-   */
-  private int mFirstVisibleItemPosition;
-
-  /**
-   * The state of scroll status
-   */
-  private int mCurrentScrollState = 0;
-
-  private WeakReference<IOnLoadMoreListener> listener;
-
-  public WXRecyclerViewOnScrollListener(IOnLoadMoreListener listener) {
-    this.listener = new WeakReference<>(listener);
-  }
-
-  @Override
-  public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-    super.onScrollStateChanged(recyclerView, newState);
-    mCurrentScrollState = newState;
-    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-    int visibleItemCount = layoutManager.getChildCount();
-    int totalItemCount = layoutManager.getItemCount();
-
-    if (visibleItemCount != 0) {
-      int bottomOffset = (totalItemCount - mLastVisibleItemPosition - 1) * (recyclerView.getHeight()) / visibleItemCount;
-      if (visibleItemCount > 0 && mCurrentScrollState == RecyclerView.SCROLL_STATE_IDLE) {
-        if (listener != null && listener.get() != null) {
-          listener.get().onLoadMore(bottomOffset);
-        }
-      }
-    }
-  }
-
-  @Override
-  public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-    super.onScrolled(recyclerView, dx, dy);
-    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-    if(listener == null){
-      return;
-    }
-    IOnLoadMoreListener iOnLoadMoreListener = listener.get();
-
-    if(iOnLoadMoreListener!=null) {
-
-      iOnLoadMoreListener.onBeforeScroll(dx, dy);
-
-      if (layoutManager instanceof LinearLayoutManager) {
-        layoutManagerType = LAYOUT_MANAGER_TYPE.LINEAR;
-        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
-        mLastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
-        int firstVisible = linearLayoutManager.findFirstVisibleItemPosition();
-        iOnLoadMoreListener.notifyAppearStateChange(firstVisible
-            , mLastVisibleItemPosition
-            , dx
-            , dy);
-      } else if (layoutManager instanceof GridLayoutManager) {
-        layoutManagerType = LAYOUT_MANAGER_TYPE.GRID;
-        GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
-        mLastVisibleItemPosition = gridLayoutManager.findLastVisibleItemPosition();
-        iOnLoadMoreListener.notifyAppearStateChange(gridLayoutManager.findFirstVisibleItemPosition()
-            , mLastVisibleItemPosition
-            , dx
-            , dy);
-
-      } else if (layoutManager instanceof StaggeredGridLayoutManager) {
-        layoutManagerType = LAYOUT_MANAGER_TYPE.STAGGERED_GRID;
-        StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
-        int newSpanCount = staggeredGridLayoutManager.getSpanCount();
-        if (mLastPositions == null || newSpanCount != mLastPositions.length) {
-          mLastPositions = new int[newSpanCount];
-        }
-        if (mFirstPositions == null || newSpanCount != mFirstPositions.length) {
-          mFirstPositions = new int[newSpanCount];
-        }
-        //avoid crash of support-v7 original bug
-        try{
-          staggeredGridLayoutManager.findFirstVisibleItemPositions(mFirstPositions);
-          mFirstVisibleItemPosition = findMin(mFirstPositions);
-          staggeredGridLayoutManager.findLastVisibleItemPositions(mLastPositions);
-          mLastVisibleItemPosition = findMax(mLastPositions);
-          iOnLoadMoreListener.notifyAppearStateChange(
-              mFirstVisibleItemPosition
-              , mLastVisibleItemPosition
-              , dx
-              , dy);
-
-        }catch(Exception e){
-          e.printStackTrace();
-          WXLogUtils.e(e.toString());
-        }
-
-      } else {
-        throw new RuntimeException(
-            "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
-      }
-    }
-  }
-
-  private int findMax(int[] lastPositions) {
-    int max = lastPositions[0];
-    for (int value : lastPositions) {
-      if (value > max) {
-        max = value;
-      }
-    }
-    return max;
-  }
-
-  private int findMin(int[] firstPositions) {
-    int min = firstPositions[0];
-    for (int value : firstPositions) {
-      if (value < min) {
-        min = value;
-      }
-    }
-    return min;
-  }
-
-  public enum LAYOUT_MANAGER_TYPE {
-    LINEAR,
-    GRID,
-    STAGGERED_GRID
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/circlebar/CircleProgressBar.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/circlebar/CircleProgressBar.java
deleted file mode 100644
index 7780624..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/circlebar/CircleProgressBar.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.refresh.circlebar;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.RadialGradient;
-import android.graphics.Shader;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.animation.Animation;
-import android.widget.ImageView;
-
-/**
- * Modify of android.support.v4
- */
-@SuppressLint("AppCompatCustomView")
-public class CircleProgressBar extends ImageView {
-
-  private static final int KEY_SHADOW_COLOR = 0x1E000000;
-  private static final int FILL_SHADOW_COLOR = 0x3D000000;
-  private static final float X_OFFSET = 0f;
-  private static final float Y_OFFSET = 1.75f;
-  private static final float SHADOW_RADIUS = 3.5f;
-  private static final int SHADOW_ELEVATION = 4;
-
-  public static final int DEFAULT_CIRCLE_BG_LIGHT = 0xFFFAFAFA;
-  public static final int DEFAULT_CIRCLE_COLOR = 0xFFF00000;
-  private static final int DEFAULT_CIRCLE_DIAMETER = 40;
-  private static final int STROKE_WIDTH_LARGE = 3;
-
-  private Animation.AnimationListener mListener;
-  private int mShadowRadius;
-  private int mBackGroundColor;
-  private int mProgressColor;
-  private int mProgressStokeWidth;
-  private int mArrowWidth;
-  private int mArrowHeight;
-  private int mProgress;
-  private int mMax;
-  private int mDiameter;
-  private int mInnerRadius;
-  private boolean mShowArrow;
-  public MaterialProgressDrawable mProgressDrawable;
-  private ShapeDrawable mBgCircle;
-  private boolean mCircleBackgroundEnabled;
-  private int[] mColors = new int[]{Color.BLACK};
-
-  public CircleProgressBar(Context context) {
-    super(context);
-    init(context, null, 0);
-
-  }
-
-  public CircleProgressBar(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    init(context, attrs, 0);
-
-  }
-
-  public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
-    super(context, attrs, defStyleAttr);
-    init(context, attrs, defStyleAttr);
-  }
-
-  private void init(Context context, AttributeSet attrs, int defStyleAttr) {
-
-    final float density = getContext().getResources().getDisplayMetrics().density;
-    mBackGroundColor = DEFAULT_CIRCLE_BG_LIGHT;
-    mProgressColor = DEFAULT_CIRCLE_COLOR;
-    mColors = new int[]{mProgressColor};
-    mInnerRadius = -1;
-    mProgressStokeWidth = (int) (STROKE_WIDTH_LARGE * density);
-    mArrowWidth =  -1;
-    mArrowHeight = -1;
-    mShowArrow = true;
-    mCircleBackgroundEnabled = true;
-    mProgress = 0;
-    mMax = 100;
-    mProgressDrawable = new MaterialProgressDrawable(getContext(), this);
-    super.setImageDrawable(mProgressDrawable);
-  }
-
-  public void setProgressBackGroundColor(int color) {
-    this.mBackGroundColor = color;
-  }
-
-  private boolean elevationSupported() {
-    return android.os.Build.VERSION.SDK_INT >= 21;
-  }
-
-  @Override
-  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    if (!elevationSupported()) {
-      setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight()
-                                                                   + mShadowRadius * 2);
-    }
-  }
-
-  public int getProgressStokeWidth() {
-    return mProgressStokeWidth;
-  }
-
-  public void setProgressStokeWidth(int mProgressStokeWidth) {
-    final float density = getContext().getResources().getDisplayMetrics().density;
-    this.mProgressStokeWidth = (int) (mProgressStokeWidth * density);
-  }
-
-  @Override
-  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-    super.onLayout(changed, left, top, right, bottom);
-    final float density = getContext().getResources().getDisplayMetrics().density;
-    mDiameter = Math.min(getMeasuredWidth(), getMeasuredHeight());
-    if (mDiameter <= 0) {
-      mDiameter = (int) density * DEFAULT_CIRCLE_DIAMETER;
-    }
-    if (getBackground() == null && mCircleBackgroundEnabled) {
-      final int shadowYOffset = (int) (density * Y_OFFSET);
-      final int shadowXOffset = (int) (density * X_OFFSET);
-      mShadowRadius = (int) (density * SHADOW_RADIUS);
-
-      if (elevationSupported()) {
-        if(mBgCircle == null) {
-          mBgCircle = new ShapeDrawable(new OvalShape());
-        }
-        ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
-      } else {
-        if(!(mBgCircle != null &&
-            mBgCircle.getShape() instanceof  OvalShadow &&
-            ((OvalShadow) mBgCircle.getShape()).mCircleDiameter == (mDiameter - mShadowRadius * 2) &&
-            ((OvalShadow) mBgCircle.getShape()).mShadowRadius == mShadowRadius)) {
-          OvalShape oval = new OvalShadow(mShadowRadius, mDiameter - mShadowRadius * 2);
-          mBgCircle = new ShapeDrawable(oval);
-        }
-        ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, mBgCircle.getPaint());
-        mBgCircle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
-                                            KEY_SHADOW_COLOR);
-        final int padding = (int) mShadowRadius;
-        // set padding so the inner image sits correctly within the shadow.
-        setPadding(padding, padding, padding, padding);
-      }
-      mBgCircle.getPaint().setColor(mBackGroundColor);
-      setBackgroundDrawable(mBgCircle);
-    }
-    mProgressDrawable.setBackgroundColor(mBackGroundColor);
-    mProgressDrawable.setColorSchemeColors(mColors);
-    if (isShowArrow()) {
-      mProgressDrawable.setArrowScale(1f);
-      mProgressDrawable.showArrow(true);
-    }
-    super.setImageDrawable(null);
-    super.setImageDrawable(mProgressDrawable);
-    mProgressDrawable.setAlpha(255);
-    if (getVisibility() == VISIBLE) {
-      mProgressDrawable.setStartEndTrim(0, (float) 0.8);
-    }
-  }
-
-  public boolean isShowArrow() {
-    return mShowArrow;
-  }
-
-  public void setShowArrow(boolean showArrow) {
-    this.mShowArrow = showArrow;
-  }
-
-  public void setAnimationListener(Animation.AnimationListener listener) {
-    mListener = listener;
-  }
-
-  @Override
-  public void onAnimationStart() {
-    super.onAnimationStart();
-    if (mListener != null) {
-      mListener.onAnimationStart(getAnimation());
-    }
-  }
-
-  @Override
-  public void onAnimationEnd() {
-    super.onAnimationEnd();
-    if (mListener != null) {
-      mListener.onAnimationEnd(getAnimation());
-    }
-  }
-
-  /**
-   * Set the colors used in the progress animation. The first
-   * color will also be the color of the bar that grows in response to a user
-   * swipe gesture.
-   *
-   * @param colors
-   */
-  public void setColorSchemeColors(int... colors) {
-    mColors = colors;
-    if (mProgressDrawable != null) {
-      mProgressDrawable.setColorSchemeColors(colors);
-    }
-  }
-
-  /**
-   * Update the background color of the mBgCircle image view.
-   */
-  public void setBackgroundColorResource(int colorRes) {
-    if (getBackground() instanceof ShapeDrawable) {
-      final Resources res = getResources();
-      ((ShapeDrawable) getBackground()).getPaint().setColor(res.getColor(colorRes));
-    }
-  }
-
-  public void setBackgroundColor(int color) {
-    if (getBackground() instanceof ShapeDrawable) {
-      ((ShapeDrawable) getBackground()).getPaint().setColor(color);
-    }
-  }
-
-  public int getMax() {
-    return mMax;
-  }
-
-  public void setMax(int max) {
-    mMax = max;
-  }
-
-  public int getProgress() {
-    return mProgress;
-  }
-
-  public void setProgress(int progress) {
-    if (getMax() > 0) {
-      mProgress = progress;
-    }
-    invalidate();
-  }
-
-  public boolean circleBackgroundEnabled() {
-    return mCircleBackgroundEnabled;
-  }
-
-  public void setCircleBackgroundEnabled(boolean enableCircleBackground) {
-    this.mCircleBackgroundEnabled = enableCircleBackground;
-  }
-
-  @Override
-  protected void onAttachedToWindow() {
-    super.onAttachedToWindow();
-    if (mProgressDrawable != null) {
-      mProgressDrawable.stop();
-      mProgressDrawable.setVisible(getVisibility() == VISIBLE, false);
-    }
-  }
-
-  @Override
-  protected void onDetachedFromWindow() {
-    super.onDetachedFromWindow();
-    if (mProgressDrawable != null) {
-      mProgressDrawable.stop();
-      mProgressDrawable.setVisible(false, false);
-    }
-  }
-
-  private class OvalShadow extends OvalShape {
-
-    private RadialGradient mRadialGradient;
-    private int mShadowRadius;
-    private Paint mShadowPaint;
-    private int mCircleDiameter;
-
-    public OvalShadow(int shadowRadius, int circleDiameter) {
-      super();
-      mShadowPaint = new Paint();
-      mShadowRadius = shadowRadius;
-      mCircleDiameter = circleDiameter;
-      mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,
-                                           mShadowRadius, new int[]{
-          FILL_SHADOW_COLOR, Color.TRANSPARENT
-      }, null, Shader.TileMode.CLAMP);
-      mShadowPaint.setShader(mRadialGradient);
-    }
-
-    @Override
-    public void draw(Canvas canvas, Paint paint) {
-      final int viewWidth = CircleProgressBar.this.getWidth();
-      final int viewHeight = CircleProgressBar.this.getHeight();
-      canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),
-                        mShadowPaint);
-      canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);
-    }
-  }
-
-  public void start() {
-    mProgressDrawable.start();
-  }
-
-  public void setStartEndTrim(float startAngle, float endAngle) {
-    mProgressDrawable.setStartEndTrim(startAngle, endAngle);
-  }
-
-  public void stop() {
-    mProgressDrawable.stop();
-  }
-
-  public void setProgressRotation(float rotation) {
-    mProgressDrawable.setProgressRotation(rotation);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/circlebar/MaterialProgressDrawable.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/circlebar/MaterialProgressDrawable.java
deleted file mode 100644
index 476e6c1..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/circlebar/MaterialProgressDrawable.java
+++ /dev/null
@@ -1,797 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.refresh.circlebar;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.v4.view.animation.FastOutSlowInInterpolator;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.Transformation;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-
-/**
- * Copy of android.support.v4
- */
-class MaterialProgressDrawable extends Drawable implements Animatable {
-
-  private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-  private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
-
-  private static final float FULL_ROTATION = 1080.0f;
-
-  @Retention(RetentionPolicy.CLASS)
-  @IntDef({LARGE, DEFAULT})
-  public @interface ProgressDrawableSize {
-
-  }
-
-  // Maps to ProgressBar.Large style
-  static final int LARGE = 0;
-  // Maps to ProgressBar default style
-  static final int DEFAULT = 1;
-
-  // Maps to ProgressBar default style
-  private static final int CIRCLE_DIAMETER = 40;
-  private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width
-  private static final float STROKE_WIDTH = 2.5f;
-
-  // Maps to ProgressBar.Large style
-  private static final int CIRCLE_DIAMETER_LARGE = 56;
-  private static final float CENTER_RADIUS_LARGE = 12.5f;
-  private static final float STROKE_WIDTH_LARGE = 3f;
-
-  private final int[] COLORS = new int[]{
-      Color.BLACK
-  };
-
-  /**
-   * The value in the linear interpolator for animating the drawable at which
-   * the color transition should start
-   */
-  private static final float COLOR_START_DELAY_OFFSET = 0.75f;
-  private static final float END_TRIM_START_DELAY_OFFSET = 0.5f;
-  private static final float START_TRIM_DURATION_OFFSET = 0.5f;
-
-  /** The duration of a single progress spin in milliseconds. */
-  private static final int ANIMATION_DURATION = 1332;
-
-  /** The number of points in the progress "star". */
-  private static final float NUM_POINTS = 5f;
-  /** The list of animators operating on this drawable. */
-  private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();
-
-  /** The indicator ring, used to manage animation state. */
-  private final Ring mRing;
-
-  /** Canvas rotation in degrees. */
-  private float mRotation;
-
-  /** Layout info for the arrowhead in dp */
-  private static final int ARROW_WIDTH = 10;
-  private static final int ARROW_HEIGHT = 5;
-  private static final float ARROW_OFFSET_ANGLE = 5;
-
-  /** Layout info for the arrowhead for the large spinner in dp */
-  private static final int ARROW_WIDTH_LARGE = 12;
-  private static final int ARROW_HEIGHT_LARGE = 6;
-  private static final float MAX_PROGRESS_ARC = .8f;
-
-  private Resources mResources;
-  private View mParent;
-  private Animation mAnimation;
-  private float mRotationCount;
-  private double mWidth;
-  private double mHeight;
-  boolean mFinishing;
-
-  public MaterialProgressDrawable(Context context, View parent) {
-    mParent = parent;
-    mResources = context.getResources();
-
-    mRing = new Ring(mCallback);
-    mRing.setColors(COLORS);
-
-    updateSizes(DEFAULT);
-    setupAnimators();
-  }
-
-  private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,
-                                 double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {
-    final Ring ring = mRing;
-    final DisplayMetrics metrics = mResources.getDisplayMetrics();
-    final float screenDensity = metrics.density;
-
-    mWidth = progressCircleWidth * screenDensity;
-    mHeight = progressCircleHeight * screenDensity;
-    ring.setStrokeWidth((float) strokeWidth * screenDensity);
-    ring.setCenterRadius(centerRadius * screenDensity);
-    ring.setColorIndex(0);
-    ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);
-    ring.setInsets((int) mWidth, (int) mHeight);
-  }
-
-  /**
-   * Set the overall size for the progress spinner. This updates the radius
-   * and stroke width of the ring.
-   *
-   * @param size One of {@link MaterialProgressDrawable.LARGE} or
-   *            {@link MaterialProgressDrawable.DEFAULT}
-   */
-  public void updateSizes(@ProgressDrawableSize int size) {
-    if (size == LARGE) {
-      setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,
-                        STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);
-    } else {
-      setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,
-                        ARROW_WIDTH, ARROW_HEIGHT);
-    }
-  }
-
-  /**
-   * @param show Set to true to display the arrowhead on the progress spinner.
-   */
-  public void showArrow(boolean show) {
-    mRing.setShowArrow(show);
-  }
-
-  /**
-   * @param scale Set the scale of the arrowhead for the spinner.
-   */
-  public void setArrowScale(float scale) {
-    mRing.setArrowScale(scale);
-  }
-
-  /**
-   * Set the start and end trim for the progress spinner arc.
-   *
-   * @param startAngle start angle
-   * @param endAngle end angle
-   */
-  public void setStartEndTrim(float startAngle, float endAngle) {
-    mRing.setStartTrim(startAngle);
-    mRing.setEndTrim(endAngle);
-  }
-
-  /**
-   * Set the amount of rotation to apply to the progress spinner.
-   *
-   * @param rotation Rotation is from [0..1]
-   */
-  public void setProgressRotation(float rotation) {
-    mRing.setRotation(rotation);
-  }
-
-  /**
-   * Update the background color of the circle image view.
-   */
-  public void setBackgroundColor(int color) {
-    mRing.setBackgroundColor(color);
-  }
-
-  /**
-   * Set the colors used in the progress animation from color resources.
-   * The first color will also be the color of the bar that grows in response
-   * to a user swipe gesture.
-   *
-   * @param colors
-   */
-  public void setColorSchemeColors(int... colors) {
-    mRing.setColors(colors);
-    mRing.setColorIndex(0);
-  }
-
-  @Override
-  public int getIntrinsicHeight() {
-    return (int) mHeight;
-  }
-
-  @Override
-  public int getIntrinsicWidth() {
-    return (int) mWidth;
-  }
-
-  @Override
-  public void draw(Canvas c) {
-    final Rect bounds = getBounds();
-    final int saveCount = c.save();
-    c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());
-    mRing.draw(c, bounds);
-    c.restoreToCount(saveCount);
-  }
-
-  @Override
-  public void setAlpha(int alpha) {
-    mRing.setAlpha(alpha);
-  }
-
-  public int getAlpha() {
-    return mRing.getAlpha();
-  }
-
-  @Override
-  public void setColorFilter(ColorFilter colorFilter) {
-    mRing.setColorFilter(colorFilter);
-  }
-
-  @SuppressWarnings("unused")
-  void setRotation(float rotation) {
-    mRotation = rotation;
-    invalidateSelf();
-  }
-
-  @SuppressWarnings("unused")
-  private float getRotation() {
-    return mRotation;
-  }
-
-  @Override
-  public int getOpacity() {
-    return PixelFormat.TRANSLUCENT;
-  }
-
-  @Override
-  public boolean isRunning() {
-    final ArrayList<Animation> animators = mAnimators;
-    final int N = animators.size();
-    for (int i = 0; i < N; i++) {
-      final Animation animator = animators.get(i);
-      if (animator.hasStarted() && !animator.hasEnded()) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  @Override
-  public void start() {
-    mAnimation.reset();
-    mRing.storeOriginals();
-    // Already showing some part of the ring
-    if (mRing.getEndTrim() != mRing.getStartTrim()) {
-      mFinishing = true;
-      mAnimation.setDuration(ANIMATION_DURATION / 2);
-      mParent.startAnimation(mAnimation);
-    } else {
-      mRing.setColorIndex(0);
-      mRing.resetOriginals();
-      mAnimation.setDuration(ANIMATION_DURATION);
-      mParent.startAnimation(mAnimation);
-    }
-  }
-
-  @Override
-  public void stop() {
-    mParent.clearAnimation();
-    setRotation(0);
-    mRing.setShowArrow(false);
-    mRing.setColorIndex(0);
-    mRing.resetOriginals();
-  }
-
-  private float getMinProgressArc(Ring ring) {
-    return (float) Math.toRadians(
-        ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
-  }
-
-  // Adapted from ArgbEvaluator.java
-  private int evaluateColorChange(float fraction, int startValue, int endValue) {
-    int startInt = (Integer) startValue;
-    int startA = (startInt >> 24) & 0xff;
-    int startR = (startInt >> 16) & 0xff;
-    int startG = (startInt >> 8) & 0xff;
-    int startB = startInt & 0xff;
-
-    int endInt = (Integer) endValue;
-    int endA = (endInt >> 24) & 0xff;
-    int endR = (endInt >> 16) & 0xff;
-    int endG = (endInt >> 8) & 0xff;
-    int endB = endInt & 0xff;
-
-    return (int) ((startA + (int) (fraction * (endA - startA))) << 24) |
-           (int) ((startR + (int) (fraction * (endR - startR))) << 16) |
-           (int) ((startG + (int) (fraction * (endG - startG))) << 8) |
-           (int) ((startB + (int) (fraction * (endB - startB))));
-  }
-
-  /**
-   * Update the ring color if this is within the last 25% of the animation.
-   * The new ring color will be a translation from the starting ring color to
-   * the next color.
-   */
-  private void updateRingColor(float interpolatedTime, Ring ring) {
-    if (interpolatedTime > COLOR_START_DELAY_OFFSET) {
-      // scale the interpolatedTime so that the full
-      // transformation from 0 - 1 takes place in the
-      // remaining time
-      ring.setColor(evaluateColorChange((interpolatedTime - COLOR_START_DELAY_OFFSET)
-                                        / (1.0f - COLOR_START_DELAY_OFFSET), ring.getStartingColor(),
-                                        ring.getNextColor()));
-    }
-  }
-
-  private void applyFinishTranslation(float interpolatedTime, Ring ring) {
-    // shrink back down and complete a full rotation before
-    // starting other circles
-    // Rotation goes between [0..1].
-    updateRingColor(interpolatedTime, ring);
-    float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC)
-                                    + 1f);
-    final float minProgressArc = getMinProgressArc(ring);
-    final float startTrim = ring.getStartingStartTrim()
-                            + (ring.getStartingEndTrim() - minProgressArc - ring.getStartingStartTrim())
-                              * interpolatedTime;
-    ring.setStartTrim(startTrim);
-    ring.setEndTrim(ring.getStartingEndTrim());
-    final float rotation = ring.getStartingRotation()
-                           + ((targetRotation - ring.getStartingRotation()) * interpolatedTime);
-    ring.setRotation(rotation);
-  }
-
-  private void setupAnimators() {
-    final Ring ring = mRing;
-    final Animation animation = new Animation() {
-      @Override
-      public void applyTransformation(float interpolatedTime, Transformation t) {
-        if (mFinishing) {
-          applyFinishTranslation(interpolatedTime, ring);
-        } else {
-          // The minProgressArc is calculated from 0 to create an
-          // angle that matches the stroke width.
-          final float minProgressArc = getMinProgressArc(ring);
-          final float startingEndTrim = ring.getStartingEndTrim();
-          final float startingTrim = ring.getStartingStartTrim();
-          final float startingRotation = ring.getStartingRotation();
-
-          updateRingColor(interpolatedTime, ring);
-
-          // Moving the start trim only occurs in the first 50% of a
-          // single ring animation
-          if (interpolatedTime <= START_TRIM_DURATION_OFFSET) {
-            // scale the interpolatedTime so that the full
-            // transformation from 0 - 1 takes place in the
-            // remaining time
-            final float scaledTime = (interpolatedTime)
-                                     / (1.0f - START_TRIM_DURATION_OFFSET);
-            final float startTrim = startingTrim
-                                    + ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR
-                .getInterpolation(scaledTime));
-            ring.setStartTrim(startTrim);
-          }
-
-          // Moving the end trim starts after 50% of a single ring
-          // animation completes
-          if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) {
-            // scale the interpolatedTime so that the full
-            // transformation from 0 - 1 takes place in the
-            // remaining time
-            final float minArc = MAX_PROGRESS_ARC - minProgressArc;
-            float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET)
-                               / (1.0f - START_TRIM_DURATION_OFFSET);
-            final float endTrim = startingEndTrim
-                                  + (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime));
-            ring.setEndTrim(endTrim);
-          }
-
-          final float rotation = startingRotation + (0.25f * interpolatedTime);
-          ring.setRotation(rotation);
-
-          float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime)
-                                + (FULL_ROTATION * (mRotationCount / NUM_POINTS));
-          setRotation(groupRotation);
-        }
-      }
-    };
-    animation.setRepeatCount(Animation.INFINITE);
-    animation.setRepeatMode(Animation.RESTART);
-    animation.setInterpolator(LINEAR_INTERPOLATOR);
-    animation.setAnimationListener(new Animation.AnimationListener() {
-
-      @Override
-      public void onAnimationStart(Animation animation) {
-        mRotationCount = 0;
-      }
-
-      @Override
-      public void onAnimationEnd(Animation animation) {
-        // do nothing
-      }
-
-      @Override
-      public void onAnimationRepeat(Animation animation) {
-        ring.storeOriginals();
-        ring.goToNextColor();
-        ring.setStartTrim(ring.getEndTrim());
-        if (mFinishing) {
-          // finished closing the last ring from the swipe gesture; go
-          // into progress mode
-          mFinishing = false;
-          animation.setDuration(ANIMATION_DURATION);
-          ring.setShowArrow(false);
-        } else {
-          mRotationCount = (mRotationCount + 1) % (NUM_POINTS);
-        }
-      }
-    });
-    mAnimation = animation;
-  }
-
-  private final Callback mCallback = new Callback() {
-    @Override
-    public void invalidateDrawable(Drawable d) {
-      invalidateSelf();
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable d, Runnable what, long when) {
-      scheduleSelf(what, when);
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable d, Runnable what) {
-      unscheduleSelf(what);
-    }
-  };
-
-  private static class Ring {
-
-    private final RectF mTempBounds = new RectF();
-    private final Paint mPaint = new Paint();
-    private final Paint mArrowPaint = new Paint();
-
-    private final Callback mCallback;
-
-    private float mStartTrim = 0.0f;
-    private float mEndTrim = 0.0f;
-    private float mRotation = 0.0f;
-    private float mStrokeWidth = 5.0f;
-    private float mStrokeInset = 2.5f;
-
-    private int[] mColors;
-    // mColorIndex represents the offset into the available mColors that the
-    // progress circle should currently display. As the progress circle is
-    // animating, the mColorIndex moves by one to the next available color.
-    private int mColorIndex;
-    private float mStartingStartTrim;
-    private float mStartingEndTrim;
-    private float mStartingRotation;
-    private boolean mShowArrow;
-    private Path mArrow;
-    private float mArrowScale;
-    private double mRingCenterRadius;
-    private int mArrowWidth;
-    private int mArrowHeight;
-    private int mAlpha;
-    private final Paint mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-    private int mBackgroundColor;
-    private int mCurrentColor;
-
-    public Ring(Callback callback) {
-      mCallback = callback;
-
-      mPaint.setStrokeCap(Paint.Cap.SQUARE);
-      mPaint.setAntiAlias(true);
-      mPaint.setStyle(Style.STROKE);
-
-      mArrowPaint.setStyle(Style.FILL);
-      mArrowPaint.setAntiAlias(true);
-    }
-
-    public void setBackgroundColor(int color) {
-      mBackgroundColor = color;
-    }
-
-    /**
-     * Set the dimensions of the arrowhead.
-     *
-     * @param width Width of the hypotenuse of the arrow head
-     * @param height Height of the arrow point
-     */
-    public void setArrowDimensions(float width, float height) {
-      mArrowWidth = (int) width;
-      mArrowHeight = (int) height;
-    }
-
-    /**
-     * Draw the progress spinner
-     */
-    public void draw(Canvas c, Rect bounds) {
-      final RectF arcBounds = mTempBounds;
-      arcBounds.set(bounds);
-      arcBounds.inset(mStrokeInset, mStrokeInset);
-
-      final float startAngle = (mStartTrim + mRotation) * 360;
-      final float endAngle = (mEndTrim + mRotation) * 360;
-      float sweepAngle = endAngle - startAngle;
-
-      mPaint.setColor(mCurrentColor);
-      c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint);
-
-      drawTriangle(c, startAngle, sweepAngle, bounds);
-
-      if (mAlpha < 255) {
-        mCirclePaint.setColor(mBackgroundColor);
-        mCirclePaint.setAlpha(255 - mAlpha);
-        c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2,
-                     mCirclePaint);
-      }
-    }
-
-    private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {
-      if (mShowArrow) {
-        if (mArrow == null) {
-          mArrow = new Path();
-          mArrow.setFillType(Path.FillType.EVEN_ODD);
-        } else {
-          mArrow.reset();
-        }
-
-        // Adjust the position of the triangle so that it is inset as
-        // much as the arc, but also centered on the arc.
-        float inset = (int) mStrokeInset / 2 * mArrowScale;
-        float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());
-        float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());
-
-        // Update the path each time. This works around an issue in SKIA
-        // where concatenating a rotation matrix to a scale matrix
-        // ignored a starting negative rotation. This appears to have
-        // been fixed as of API 21.
-        mArrow.moveTo(0, 0);
-        mArrow.lineTo(mArrowWidth * mArrowScale, 0);
-        mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight
-                                                        * mArrowScale));
-        mArrow.offset(x - inset, y);
-        mArrow.close();
-        // draw a triangle
-        mArrowPaint.setColor(mCurrentColor);
-        c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),
-                 bounds.exactCenterY());
-        c.drawPath(mArrow, mArrowPaint);
-      }
-    }
-
-    /**
-     * Set the colors the progress spinner alternates between.
-     *
-     * @param colors Array of integers describing the colors. Must be non-<code>null</code>.
-     */
-    public void setColors(@NonNull int[] colors) {
-      mColors = colors;
-      // if colors are reset, make sure to reset the color index as well
-      setColorIndex(0);
-    }
-
-    /**
-     * Set the absolute color of the progress spinner. This is should only
-     * be used when animating between current and next color when the
-     * spinner is rotating.
-     *
-     * @param color int describing the color.
-     */
-    public void setColor(int color) {
-      mCurrentColor = color;
-    }
-
-    /**
-     * @param index Index into the color array of the color to display in
-     *            the progress spinner.
-     */
-    public void setColorIndex(int index) {
-      mColorIndex = index;
-      mCurrentColor = mColors[mColorIndex];
-    }
-
-    /**
-     * @return int describing the next color the progress spinner should use when drawing.
-     */
-    public int getNextColor() {
-      return mColors[getNextColorIndex()];
-    }
-
-    private int getNextColorIndex() {
-      return (mColorIndex + 1) % (mColors.length);
-    }
-
-    /**
-     * Proceed to the next available ring color. This will automatically
-     * wrap back to the beginning of colors.
-     */
-    public void goToNextColor() {
-      setColorIndex(getNextColorIndex());
-    }
-
-    public void setColorFilter(ColorFilter filter) {
-      mPaint.setColorFilter(filter);
-      invalidateSelf();
-    }
-
-    /**
-     * @param alpha Set the alpha of the progress spinner and associated arrowhead.
-     */
-    public void setAlpha(int alpha) {
-      mAlpha = alpha;
-    }
-
-    /**
-     * @return Current alpha of the progress spinner and arrowhead.
-     */
-    public int getAlpha() {
-      return mAlpha;
-    }
-
-    /**
-     * @param strokeWidth Set the stroke width of the progress spinner in pixels.
-     */
-    public void setStrokeWidth(float strokeWidth) {
-      mStrokeWidth = strokeWidth;
-      mPaint.setStrokeWidth(strokeWidth);
-      invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getStrokeWidth() {
-      return mStrokeWidth;
-    }
-
-    @SuppressWarnings("unused")
-    public void setStartTrim(float startTrim) {
-      mStartTrim = startTrim;
-      invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getStartTrim() {
-      return mStartTrim;
-    }
-
-    public float getStartingStartTrim() {
-      return mStartingStartTrim;
-    }
-
-    public float getStartingEndTrim() {
-      return mStartingEndTrim;
-    }
-
-    public int getStartingColor() {
-      return mColors[mColorIndex];
-    }
-
-    @SuppressWarnings("unused")
-    public void setEndTrim(float endTrim) {
-      mEndTrim = endTrim;
-      invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getEndTrim() {
-      return mEndTrim;
-    }
-
-    @SuppressWarnings("unused")
-    public void setRotation(float rotation) {
-      mRotation = rotation;
-      invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getRotation() {
-      return mRotation;
-    }
-
-    public void setInsets(int width, int height) {
-      final float minEdge = (float) Math.min(width, height);
-      float insets;
-      if (mRingCenterRadius <= 0 || minEdge < 0) {
-        insets = (float) Math.ceil(mStrokeWidth / 2.0f);
-      } else {
-        insets = (float) (minEdge / 2.0f - mRingCenterRadius);
-      }
-      mStrokeInset = insets;
-    }
-
-    @SuppressWarnings("unused")
-    public float getInsets() {
-      return mStrokeInset;
-    }
-
-    /**
-     * @param centerRadius Inner radius in px of the circle the progress
-     *            spinner arc traces.
-     */
-    public void setCenterRadius(double centerRadius) {
-      mRingCenterRadius = centerRadius;
-    }
-
-    public double getCenterRadius() {
-      return mRingCenterRadius;
-    }
-
-    /**
-     * @param show Set to true to show the arrow head on the progress spinner.
-     */
-    public void setShowArrow(boolean show) {
-      if (mShowArrow != show) {
-        mShowArrow = show;
-        invalidateSelf();
-      }
-    }
-
-    /**
-     * @param scale Set the scale of the arrowhead for the spinner.
-     */
-    public void setArrowScale(float scale) {
-      if (scale != mArrowScale) {
-        mArrowScale = scale;
-        invalidateSelf();
-      }
-    }
-
-    /**
-     * @return The amount the progress spinner is currently rotated, between [0..1].
-     */
-    public float getStartingRotation() {
-      return mStartingRotation;
-    }
-
-    /**
-     * If the start / end trim are offset to begin with, store them so that
-     * animation starts from that offset.
-     */
-    public void storeOriginals() {
-      mStartingStartTrim = mStartTrim;
-      mStartingEndTrim = mEndTrim;
-      mStartingRotation = mRotation;
-    }
-
-    /**
-     * Reset the progress spinner to default rotation, start and end angles.
-     */
-    public void resetOriginals() {
-      mStartingStartTrim = 0;
-      mStartingEndTrim = 0;
-      mStartingRotation = 0;
-      setStartTrim(0);
-      setEndTrim(0);
-      setRotation(0);
-    }
-
-    private void invalidateSelf() {
-      mCallback.invalidateDrawable(null);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/core/WXRefreshView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/core/WXRefreshView.java
deleted file mode 100644
index 7c69be8..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/core/WXRefreshView.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.refresh.core;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.taobao.weex.common.WXThread;
-import com.taobao.weex.ui.view.refresh.circlebar.CircleProgressBar;
-
-public class WXRefreshView extends FrameLayout {
-
-  private CircleProgressBar circleProgressBar;
-  private LinearLayout linearLayout;
-
-  public WXRefreshView(Context context) {
-    super(context);
-    setupViews();
-  }
-
-  public WXRefreshView(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    setupViews();
-  }
-
-  public WXRefreshView(Context context, AttributeSet attrs, int defStyleAttr) {
-    super(context, attrs, defStyleAttr);
-    setupViews();
-  }
-
-  private void setupViews() {
-    linearLayout = new LinearLayout(getContext());
-    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams
-            .MATCH_PARENT,FrameLayout
-            .LayoutParams.MATCH_PARENT);
-    linearLayout.setOrientation(LinearLayout.VERTICAL);
-    linearLayout.setGravity(Gravity.CENTER);
-    addView(linearLayout,lp);
-  }
-
-  public void setContentGravity(int gravity) {
-    if (linearLayout != null) {
-      linearLayout.setGravity(gravity);
-    }
-  }
-
-  /**
-   * Setting refresh view or loading view
-   *
-   * @param view refresh or loading
-   */
-  public void setRefreshView(final View view) {
-    if (view == null)
-      return;
-    post(WXThread.secure(new Runnable() {
-      @Override
-      public void run() {
-        View child = null;
-        View temp = view;
-        if (view.getParent() != null) {
-          ((ViewGroup) view.getParent()).removeView(view);
-        }
-        for (int i = 0;i<((ViewGroup)temp).getChildCount(); i++) {
-          child = ((ViewGroup) temp).getChildAt(i);
-          if (child instanceof CircleProgressBar)
-            circleProgressBar = (CircleProgressBar) child;
-        }
-        linearLayout.addView(temp);
-      }
-    }));
-  }
-
-  /**
-   * Set loading_indicator bgColor
-   *
-   * @param color
-   */
-  public void setProgressBgColor(int color) {
-    if (circleProgressBar != null) {
-      circleProgressBar.setBackgroundColor(color);
-    }
-  }
-
-  /**
-   * Set loading_indicator color
-   *
-   * @param color
-   */
-  public void setProgressColor(int color) {
-    if (circleProgressBar != null) {
-      circleProgressBar.setColorSchemeColors(color);
-    }
-  }
-
-  protected void startAnimation() {
-    if (circleProgressBar != null) {
-      circleProgressBar.start();
-    }
-  }
-
-  /**
-   * Set the start and end trim for the progress spinner arc.
-   *
-   * @param startAngle start angle
-   * @param endAngle end angle
-   */
-  public void setStartEndTrim(float startAngle, float endAngle) {
-    if (circleProgressBar != null) {
-      circleProgressBar.setStartEndTrim(startAngle, endAngle);
-    }
-  }
-
-  protected void stopAnimation() {
-    if (circleProgressBar != null) {
-      circleProgressBar.stop();
-    }
-  }
-
-  /**
-   * Set the amount of rotation to apply to the progress spinner.
-   *
-   * @param rotation Rotation is from [0..1]
-   */
-  public void setProgressRotation(float rotation) {
-    if (circleProgressBar != null)
-      circleProgressBar.setProgressRotation(rotation);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/core/WXSwipeLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/core/WXSwipeLayout.java
deleted file mode 100644
index 91f2711..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/core/WXSwipeLayout.java
+++ /dev/null
@@ -1,854 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.refresh.core;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.v4.view.NestedScrollingChild;
-import android.support.v4.view.NestedScrollingChildHelper;
-import android.support.v4.view.NestedScrollingParent;
-import android.support.v4.view.NestedScrollingParentHelper;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewParentCompat;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.AbsListView;
-import android.widget.FrameLayout;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class WXSwipeLayout extends FrameLayout implements NestedScrollingParent, NestedScrollingChild {
-
-  private NestedScrollingParentHelper mNestedScrollingParentHelper;
-  private NestedScrollingChildHelper mNestedScrollingChildHelper;
-  private final int[] mParentScrollConsumed = new int[2];
-  private final int[] mParentOffsetInWindow = new int[2];
-  private boolean mNestedScrollInProgress;
-  private WXOnRefreshListener onRefreshListener;
-  private WXOnLoadingListener onLoadingListener;
-
-  private ViewParent mNestedScrollAcceptedParent;
-
-  private final List<OnRefreshOffsetChangedListener> mRefreshOffsetChangedListeners = new LinkedList<>();
-
-  public interface OnRefreshOffsetChangedListener {
-    void onOffsetChanged(int verticalOffset);
-  }
-
-  /**
-   * On refresh Callback, call on start refresh
-   */
-  public interface WXOnRefreshListener {
-
-    void onRefresh();
-
-    void onPullingDown(float dy, int pullOutDistance, float viewHeight);
-  }
-
-  /**
-   * On loadmore Callback, call on start loadmore
-   */
-  public interface WXOnLoadingListener {
-
-    void onLoading();
-    void onPullingUp(float dy, int pullOutDistance, float viewHeight);
-  }
-
-  static class WXRefreshAnimatorListener implements Animator.AnimatorListener {
-
-    @Override
-    public void onAnimationStart(Animator animation) {
-    }
-
-    @Override
-    public void onAnimationEnd(Animator animation) {
-    }
-
-    @Override
-    public void onAnimationCancel(Animator animation) {
-    }
-
-    @Override
-    public void onAnimationRepeat(Animator animation) {
-    }
-  }
-
-  private WXRefreshView headerView;
-  private WXRefreshView footerView;
-  private View mTargetView;
-
-  private static final int INVALID = -1;
-  private static final int PULL_REFRESH = 0;
-  private static final int LOAD_MORE = 1;
-
-  // Enable PullRefresh and Loadmore
-  private boolean mPullRefreshEnable = false;
-  private boolean mPullLoadEnable = false;
-
-  // Is Refreshing
-  volatile private boolean mRefreshing = false;
-
-  // RefreshView Height
-  private volatile float refreshViewHeight = 0;
-  private volatile float loadingViewHeight = 0;
-
-  // RefreshView Over Flow Height
-  private volatile float refreshViewFlowHeight = 0;
-  private volatile float loadingViewFlowHeight = 0;
-
-  private static final float overFlow = 1.0f;
-
-  private static final float DAMPING = 0.4f;
-
-  // Drag Action
-  private int mCurrentAction = -1;
-  private boolean isConfirm = false;
-
-  // RefreshView Attrs
-  private int mRefreshViewBgColor;
-  private int mProgressBgColor;
-  private int mProgressColor;
-
-  public WXSwipeLayout(Context context) {
-    super(context);
-    initAttrs(context, null);
-  }
-
-  public WXSwipeLayout(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    initAttrs(context, attrs);
-  }
-
-  public WXSwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-    super(context, attrs, defStyleAttr);
-    initAttrs(context, attrs);
-  }
-
-  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-  public WXSwipeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-    super(context, attrs, defStyleAttr, defStyleRes);
-    initAttrs(context, attrs);
-  }
-
-  private void initAttrs(Context context, AttributeSet attrs) {
-
-    if (getChildCount() > 1) {
-      throw new RuntimeException("WXSwipeLayout should not have more than one child");
-    }
-
-    mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
-    mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
-    setNestedScrollingEnabled(false);
-
-    if (isInEditMode() && attrs == null) {
-      return;
-    }
-
-    mRefreshViewBgColor = Color.TRANSPARENT;
-    mProgressBgColor = Color.TRANSPARENT;
-    mProgressColor = Color.RED;
-  }
-
-  @Override
-  protected void onAttachedToWindow() {
-    super.onAttachedToWindow();
-    if(mTargetView == null && getChildCount() > 0){
-      mTargetView = getChildAt(0);
-    }
-    if(mTargetView != null){
-      if(headerView == null || footerView == null){
-        setRefreshView();
-      }
-    }
-  }
-
-
-  public void addTargetView(View mInnerView){
-    this.addView(mInnerView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
-    setRefreshView();
-  }
-  /**
-   * Init refresh view or loading view
-   */
-  private void setRefreshView() {
-    // SetUp HeaderView
-    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 0);
-    headerView = new WXRefreshView(getContext());
-    headerView.setStartEndTrim(0, 0.75f);
-    headerView.setBackgroundColor(mRefreshViewBgColor);
-    headerView.setProgressBgColor(mProgressBgColor);
-    headerView.setProgressColor(mProgressColor);
-    headerView.setContentGravity(Gravity.BOTTOM);
-    addView(headerView, lp);
-
-    // SetUp FooterView
-    lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 0);
-    lp.gravity = Gravity.BOTTOM;
-    footerView = new WXRefreshView(getContext());
-    footerView.setStartEndTrim(0.5f, 1.25f);
-    footerView.setBackgroundColor(mRefreshViewBgColor);
-    footerView.setProgressBgColor(mProgressBgColor);
-    footerView.setProgressColor(mProgressColor);
-    footerView.setContentGravity(Gravity.TOP);
-    addView(footerView, lp);
-  }
-
-  @Override
-  public boolean onInterceptTouchEvent(MotionEvent ev) {
-    if ((!mPullRefreshEnable && !mPullLoadEnable)) {
-      return false;
-    }
-    if (!isEnabled() || canChildScrollUp()
-            || mRefreshing || mNestedScrollInProgress) {
-      // Fail fast if we're not in a state where a swipe is possible
-      return false;
-    }
-
-    return super.onInterceptTouchEvent(ev);
-  }
-
-  // NestedScrollingChild
-
-  @Override
-  public void setNestedScrollingEnabled(boolean enabled) {
-    mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
-  }
-
-  @Override
-  public boolean isNestedScrollingEnabled() {
-    return mNestedScrollingChildHelper.isNestedScrollingEnabled();
-  }
-
-  @Override
-  public boolean startNestedScroll(int axes) {
-    boolean result = mNestedScrollingChildHelper.startNestedScroll(axes);
-    if(result){
-      if(mNestedScrollAcceptedParent == null){
-        ViewParent parent  = this.getParent();
-        View child = this;
-        while (parent != null) {
-          if (ViewParentCompat.onStartNestedScroll(parent, child, this, axes)){
-            mNestedScrollAcceptedParent = parent;
-            break;
-          }
-          if(parent instanceof  View){
-            child = (View) parent;
-          }
-          parent = parent.getParent();
-        }
-      }
-    }
-    return result;
-  }
-
-  @Override
-  public void stopNestedScroll() {
-    mNestedScrollingChildHelper.stopNestedScroll();
-    if(mNestedScrollAcceptedParent != null){
-      mNestedScrollAcceptedParent = null;
-    }
-  }
-
-  @Override
-  public boolean hasNestedScrollingParent() {
-    return mNestedScrollingChildHelper.hasNestedScrollingParent();
-  }
-
-  @Override
-  public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
-                                      int dyUnconsumed, int[] offsetInWindow) {
-    return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
-            dxUnconsumed, dyUnconsumed, offsetInWindow);
-  }
-
-  @Override
-  public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
-    return mNestedScrollingChildHelper.dispatchNestedPreScroll(
-            dx, dy, consumed, offsetInWindow);
-  }
-
-
-
-  @Override
-  public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
-    return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
-  }
-
-  @Override
-  public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
-    return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
-  }
-
-  /*********************************** NestedScrollParent *************************************/
-
-
-  @Override
-  public boolean onNestedPreFling(View target, float velocityX,
-                                  float velocityY) {
-    if(isNestedScrollingEnabled()) {
-      return dispatchNestedPreFling(velocityX, velocityY);
-    }
-    return  false;
-  }
-
-  @Override
-  public boolean onNestedFling(View target, float velocityX, float velocityY,
-                               boolean consumed) {
-    if(isNestedScrollingEnabled()) {
-      return dispatchNestedFling(velocityX, velocityY, consumed);
-    }
-    return  false;
-  }
-
-  @Override
-  public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
-    boolean result =  isEnabled()  && !mRefreshing
-            && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
-
-    return  result;
-  }
-
-  @Override
-  public void onNestedScrollAccepted(View child, View target, int axes) {
-    mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
-    if(isNestedScrollingEnabled()){
-      startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
-      mNestedScrollInProgress = true;
-    }
-  }
-
-
-  /**
-   * With child view to processing move events
-   * @param target the child view
-   * @param dx move x
-   * @param dy move y
-   * @param consumed parent consumed move distance
-   */
-  @Override
-  public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
-    // Now let our nested parent consume the leftovers
-    final int[] parentConsumed = mParentScrollConsumed;
-    if(isNestedScrollingEnabled()){
-      if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
-        consumed[0] += parentConsumed[0];
-        consumed[1] += parentConsumed[1];
-        return;
-      }
-    }
-    if ((!mPullRefreshEnable && !mPullLoadEnable)) {
-      return;
-    }
-
-    /**
-     * when in nest-scroll, list canChildScrollUp() false,
-     * maybe parent scroll can scroll up
-     * */
-    if(!canChildScrollUp() && isNestedScrollingEnabled()){
-      if(mNestedScrollAcceptedParent != null && mNestedScrollAcceptedParent != mTargetView){
-        ViewGroup group = (ViewGroup) mNestedScrollAcceptedParent;
-        if(group.getChildCount() > 0){
-          int count = group.getChildCount();
-          for(int i=0; i<count; i++){
-            View view  = group.getChildAt(i);
-            if(view.getVisibility() != View.GONE && view.getMeasuredHeight() > 0){
-              if(view.getTop() < 0){
-                return;
-              }else{
-                break;
-              }
-            }
-          }
-        }
-      }
-    }
-
-
-
-    int spinnerDy = (int) calculateDistanceY(target, dy);
-
-    mRefreshing = false;
-
-    if (!isConfirm) {
-      if (spinnerDy < 0 && !canChildScrollUp()) {
-        mCurrentAction = PULL_REFRESH;
-        isConfirm = true;
-      } else if (spinnerDy > 0 && !canChildScrollDown() && (!mRefreshing)) {
-        mCurrentAction = LOAD_MORE;
-        isConfirm = true;
-      }
-    }
-
-    if (moveSpinner(-spinnerDy)) {
-      if (!canChildScrollUp() && mPullRefreshEnable
-              && mTargetView.getTranslationY() > 0
-              && dy > 0) {
-        consumed[1] += dy;
-      }else if (!canChildScrollDown() && mPullLoadEnable
-              && mTargetView.getTranslationY() < 0
-              && dy < 0){
-        consumed[1] += dy;
-      }else{
-        consumed[1] += spinnerDy;
-      }
-    }
-  }
-
-  @Override
-  public int getNestedScrollAxes() {
-    return mNestedScrollingParentHelper.getNestedScrollAxes();
-  }
-
-
-  /**
-   * Callback on TouchEvent.ACTION_CANCLE or TouchEvent.ACTION_UP
-   * handler : refresh or loading
-   * @param child : child view of SwipeLayout,RecyclerView or Scroller
-   */
-  @Override
-  public void onStopNestedScroll(View child) {
-    mNestedScrollingParentHelper.onStopNestedScroll(child);
-    handlerAction();
-    if(isNestedScrollingEnabled()) {
-      mNestedScrollInProgress = true;
-      stopNestedScroll();
-    }
-  }
-
-
-  @Override
-  public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
-    if(isNestedScrollingEnabled()) {
-      dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, mParentOffsetInWindow);
-    }
-  }
-
-
-
-
-
-  private double calculateDistanceY(View target, int dy) {
-    int viewHeight = target.getMeasuredHeight();
-    double ratio = (viewHeight - Math.abs(target.getY())) / 1.0d / viewHeight * DAMPING;
-    if (ratio <= 0.01d) {
-      //Filter tiny scrolling action
-      ratio = 0.01d;
-    }
-    return ratio * dy;
-  }
-
-  /**
-   * Adjust the refresh or loading view according to the size of the gesture
-   *
-   * @param distanceY move distance of Y
-   */
-  private boolean moveSpinner(float distanceY) {
-    if (mRefreshing) {
-      return false;
-    }
-
-    if (!canChildScrollUp() && mPullRefreshEnable && mCurrentAction == PULL_REFRESH) {
-      // Pull Refresh
-      LayoutParams lp = (LayoutParams) headerView.getLayoutParams();
-      lp.height += distanceY;
-      if (lp.height < 0) {
-        lp.height = 0;
-      }
-
-      if (lp.height == 0) {
-        isConfirm = false;
-        mCurrentAction = INVALID;
-      }
-      headerView.setLayoutParams(lp);
-      onRefreshListener.onPullingDown(distanceY, lp.height, refreshViewFlowHeight);
-      notifyOnRefreshOffsetChangedListener(lp.height);
-      headerView.setProgressRotation(lp.height / refreshViewFlowHeight);
-      moveTargetView(lp.height);
-      return true;
-    } else if (!canChildScrollDown() && mPullLoadEnable && mCurrentAction == LOAD_MORE) {
-      // Load more
-      LayoutParams lp = (LayoutParams) footerView.getLayoutParams();
-      lp.height -= distanceY;
-      if (lp.height < 0) {
-        lp.height = 0;
-      }
-
-      if (lp.height == 0) {
-        isConfirm = false;
-        mCurrentAction = INVALID;
-      }
-      footerView.setLayoutParams(lp);
-      onLoadingListener.onPullingUp(distanceY, lp.height, loadingViewFlowHeight);
-      footerView.setProgressRotation(lp.height / loadingViewFlowHeight);
-      moveTargetView(-lp.height);
-      return true;
-    }
-    return false;
-  }
-
-  /**
-   * Adjust contentView(Scroller or List) at refresh or loading time
-   * @param h Height of refresh view or loading view
-   */
-  private void moveTargetView(float h) {
-    mTargetView.setTranslationY(h);
-  }
-
-  /**
-   * Decide on the action refresh or loadmore
-   */
-  private void handlerAction() {
-
-    if (isRefreshing()) {
-      return;
-    }
-    isConfirm = false;
-
-    LayoutParams lp;
-    if (mPullRefreshEnable && mCurrentAction == PULL_REFRESH) {
-      lp = (LayoutParams) headerView.getLayoutParams();
-      if (lp.height >= refreshViewHeight) {
-        startRefresh(lp.height);
-      } else if (lp.height > 0) {
-        resetHeaderView(lp.height);
-      } else {
-        resetRefreshState();
-      }
-    }
-
-    if (mPullLoadEnable && mCurrentAction == LOAD_MORE) {
-      lp = (LayoutParams) footerView.getLayoutParams();
-      if (lp.height >= loadingViewHeight) {
-        startLoadmore(lp.height);
-      } else if (lp.height > 0) {
-        resetFootView(lp.height);
-      } else {
-        resetLoadmoreState();
-      }
-    }
-  }
-
-  /**
-   * Start Refresh
-   * @param headerViewHeight
-   */
-  private void startRefresh(int headerViewHeight) {
-    mRefreshing = true;
-    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, refreshViewHeight);
-    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-      @Override
-      public void onAnimationUpdate(ValueAnimator animation) {
-        LayoutParams lp = (LayoutParams) headerView.getLayoutParams();
-        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
-        notifyOnRefreshOffsetChangedListener(lp.height);
-        headerView.setLayoutParams(lp);
-        moveTargetView(lp.height);
-      }
-    });
-    animator.addListener(new WXRefreshAnimatorListener() {
-      @Override
-      public void onAnimationEnd(Animator animation) {
-        headerView.startAnimation();
-        //TODO updateLoadText
-        if (onRefreshListener != null) {
-          onRefreshListener.onRefresh();
-        }
-      }
-    });
-    animator.setDuration(300);
-    animator.start();
-  }
-
-  /**
-   * Reset refresh state
-   * @param headerViewHeight
-   */
-  private void resetHeaderView(int headerViewHeight) {
-    headerView.stopAnimation();
-    headerView.setStartEndTrim(0, 0.75f);
-    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, 0);
-    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-      @Override
-      public void onAnimationUpdate(ValueAnimator animation) {
-        LayoutParams lp = (LayoutParams) headerView.getLayoutParams();
-        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
-        notifyOnRefreshOffsetChangedListener(lp.height);
-        headerView.setLayoutParams(lp);
-        moveTargetView(lp.height);
-      }
-    });
-    animator.addListener(new WXRefreshAnimatorListener() {
-      @Override
-      public void onAnimationEnd(Animator animation) {
-        resetRefreshState();
-
-      }
-    });
-    animator.setDuration(300);
-    animator.start();
-  }
-
-  private void resetRefreshState() {
-    mRefreshing = false;
-    isConfirm = false;
-    mCurrentAction = -1;
-    //TODO updateLoadText
-  }
-
-  /**
-   * Start loadmore
-   * @param headerViewHeight
-   */
-  private void startLoadmore(int headerViewHeight) {
-    mRefreshing = true;
-    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, loadingViewHeight);
-    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-      @Override
-      public void onAnimationUpdate(ValueAnimator animation) {
-        LayoutParams lp = (LayoutParams) footerView.getLayoutParams();
-        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
-        footerView.setLayoutParams(lp);
-        moveTargetView(-lp.height);
-      }
-    });
-    animator.addListener(new WXRefreshAnimatorListener() {
-      @Override
-      public void onAnimationEnd(Animator animation) {
-        footerView.startAnimation();
-        //TODO updateLoadText
-        if (onLoadingListener != null) {
-          onLoadingListener.onLoading();
-        }
-      }
-    });
-    animator.setDuration(300);
-    animator.start();
-  }
-
-  /**
-   * Reset loadmore state
-   * @param headerViewHeight
-   */
-  private void resetFootView(int headerViewHeight) {
-    footerView.stopAnimation();
-    footerView.setStartEndTrim(0.5f, 1.25f);
-    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, 0);
-    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-      @Override
-      public void onAnimationUpdate(ValueAnimator animation) {
-        LayoutParams lp = (LayoutParams) footerView.getLayoutParams();
-        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
-        footerView.setLayoutParams(lp);
-        moveTargetView(-lp.height);
-      }
-    });
-    animator.addListener(new WXRefreshAnimatorListener() {
-      @Override
-      public void onAnimationEnd(Animator animation) {
-        resetLoadmoreState();
-
-      }
-    });
-    animator.setDuration(300);
-    animator.start();
-  }
-
-  private void resetLoadmoreState() {
-    mRefreshing = false;
-    isConfirm = false;
-    mCurrentAction = -1;
-    //TODO updateLoadText
-  }
-
-  /**
-   * Whether child view can scroll up
-   * @return
-   */
-  @SuppressLint("ObsoleteSdkInt")
-  public boolean canChildScrollUp() {
-    if (mTargetView == null) {
-      return false;
-    }
-    if (Build.VERSION.SDK_INT < 14) {
-      //The minimum version of Android platform that Weex supports is API 14,
-      //so this block should never enter.
-      if (mTargetView instanceof AbsListView) {
-        final AbsListView absListView = (AbsListView) mTargetView;
-        return absListView.getChildCount() > 0
-                && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
-                .getTop() < absListView.getPaddingTop());
-      } else {
-        return ViewCompat.canScrollVertically(mTargetView, -1) || mTargetView.getScrollY() > 0;
-      }
-    } else {
-      return ViewCompat.canScrollVertically(mTargetView, -1);
-    }
-  }
-
-  /**
-   * Whether child view can scroll down
-   * @return
-   */
-  @SuppressLint("ObsoleteSdkInt")
-  public boolean canChildScrollDown() {
-    if (mTargetView == null) {
-      return false;
-    }
-    if (Build.VERSION.SDK_INT < 14) {
-      //The minimum version of Android platform that Weex supports is API 14,
-      //so this block should never enter.
-      if (mTargetView instanceof AbsListView) {
-        final AbsListView absListView = (AbsListView) mTargetView;
-        if (absListView.getChildCount() > 0) {
-          int lastChildBottom = absListView.getChildAt(absListView.getChildCount() - 1)
-                  .getBottom();
-          return absListView.getLastVisiblePosition() == absListView.getAdapter().getCount() - 1
-                  && lastChildBottom <= absListView.getMeasuredHeight();
-        } else {
-          return false;
-        }
-
-      } else {
-        return ViewCompat.canScrollVertically(mTargetView, 1) || mTargetView.getScrollY() > 0;
-      }
-    } else {
-      return ViewCompat.canScrollVertically(mTargetView, 1);
-    }
-  }
-
-  public float dipToPx(Context context, float value) {
-    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
-    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, metrics);
-  }
-
-  public void setOnLoadingListener(WXOnLoadingListener onLoadingListener) {
-    this.onLoadingListener = onLoadingListener;
-  }
-
-  public void setOnRefreshListener(WXOnRefreshListener onRefreshListener) {
-    this.onRefreshListener = onRefreshListener;
-  }
-
-  @SuppressWarnings("unused")
-  public void addOnRefreshOffsetChangedListener(@Nullable OnRefreshOffsetChangedListener listener) {
-    if(listener != null && !mRefreshOffsetChangedListeners.contains(listener)) {
-      mRefreshOffsetChangedListeners.add(listener);
-    }
-  }
-
-  @SuppressWarnings("unused")
-  public boolean removeOnRefreshOffsetChangedListener(@Nullable OnRefreshOffsetChangedListener listener) {
-    if(listener != null) {
-      return mRefreshOffsetChangedListeners.remove(listener);
-    }
-    return false;
-  }
-
-  private void notifyOnRefreshOffsetChangedListener(int verticalOffset) {
-    int size = mRefreshOffsetChangedListeners.size();
-    OnRefreshOffsetChangedListener listener;
-    for (int i=0; i<size; i++) {
-      if(i >= mRefreshOffsetChangedListeners.size()){
-        break;
-      }
-      listener = mRefreshOffsetChangedListeners.get(i);
-
-      if (listener != null) {
-        listener.onOffsetChanged(verticalOffset);
-      }
-    }
-  }
-
-  /**
-   * Callback on refresh finish
-   */
-  public void finishPullRefresh() {
-    if (mCurrentAction == PULL_REFRESH) {
-      resetHeaderView(headerView == null ? 0 : headerView.getMeasuredHeight());
-    }
-  }
-
-  /**
-   * Callback on loadmore finish
-   */
-  public void finishPullLoad() {
-    if (mCurrentAction == LOAD_MORE) {
-      resetFootView(footerView == null ? 0 : footerView.getMeasuredHeight());
-    }
-  }
-
-  public WXRefreshView getHeaderView() {
-    return headerView;
-  }
-
-  public WXRefreshView getFooterView() {
-    return footerView;
-  }
-
-  public boolean isPullLoadEnable() {
-    return mPullLoadEnable;
-  }
-
-  public void setPullLoadEnable(boolean mPullLoadEnable) {
-    this.mPullLoadEnable = mPullLoadEnable;
-  }
-
-  public boolean isPullRefreshEnable() {
-    return mPullRefreshEnable;
-  }
-
-  public void setPullRefreshEnable(boolean mPullRefreshEnable) {
-    this.mPullRefreshEnable = mPullRefreshEnable;
-  }
-
-  public boolean isRefreshing() {
-    return mRefreshing;
-  }
-
-  public void setRefreshHeight(int height) {
-    refreshViewHeight = height;
-    refreshViewFlowHeight = refreshViewHeight * overFlow;
-  }
-
-  public void setLoadingHeight(int height) {
-    loadingViewHeight = height;
-    loadingViewFlowHeight = loadingViewHeight * overFlow;
-  }
-
-  public void setRefreshBgColor(int color) {
-    headerView.setBackgroundColor(color);
-  }
-
-  public void setLoadingBgColor(int color) {
-    footerView.setBackgroundColor(color);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BaseBounceView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BaseBounceView.java
deleted file mode 100644
index ca8f510..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BaseBounceView.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.refresh.wrapper;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.support.v7.widget.OrientationHelper;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.view.WXLoadingLayout;
-import com.taobao.weex.ui.view.WXRefreshLayout;
-import com.taobao.weex.ui.view.refresh.core.WXRefreshView;
-import com.taobao.weex.ui.view.refresh.core.WXSwipeLayout;
-import com.taobao.weex.utils.WXResourceUtils;
-import com.taobao.weex.utils.WXUtils;
-
-/**
- * BounceView(SwipeLayout) contains Scroller/List and refresh/loading view
- * @param <T> InnerView
- */
-public abstract class BaseBounceView<T extends View> extends FrameLayout {
-
-    private int mOrientation = OrientationHelper.VERTICAL;
-    protected WXSwipeLayout swipeLayout;
-    private T mInnerView;
-
-    public BaseBounceView(Context context,int orientation) {
-        this(context, null,orientation);
-    }
-
-    public BaseBounceView(Context context, AttributeSet attrs,int orientation) {
-        super(context, attrs);
-        mOrientation = orientation;
-    }
-
-    public int getOrientation(){
-        return mOrientation;
-    }
-
-    public void init(Context context) {
-        createBounceView(context);
-    }
-
-    boolean isVertical(){
-        return mOrientation==OrientationHelper.VERTICAL;
-    }
-
-    public void setOnRefreshListener(WXSwipeLayout.WXOnRefreshListener onRefreshListener) {
-        if (swipeLayout != null)
-            swipeLayout.setOnRefreshListener(onRefreshListener);
-    }
-
-    public void setOnLoadingListener(WXSwipeLayout.WXOnLoadingListener onLoadingListener) {
-        if (swipeLayout != null)
-            swipeLayout.setOnLoadingListener(onLoadingListener);
-    }
-
-    public void finishPullRefresh() {
-        if (swipeLayout != null)
-            swipeLayout.finishPullRefresh();
-    }
-
-    public void finishPullLoad() {
-        if (swipeLayout != null)
-            swipeLayout.finishPullLoad();
-    }
-
-    /**
-     * Init wipelayout
-     */
-    private WXSwipeLayout createBounceView(Context context) {
-        swipeLayout = new WXSwipeLayout(context);
-        swipeLayout.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
-        mInnerView = setInnerView(context);
-        if (mInnerView == null)
-            return null;
-        swipeLayout.addTargetView(mInnerView);
-        addView(swipeLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-        return swipeLayout;
-    }
-
-    /**
-     * @return the child of swipelayout : recyclerview or scrollview
-     */
-    public T getInnerView() {
-        return mInnerView;
-    }
-
-    public abstract T setInnerView(Context context);
-
-    /**
-     *
-     * @param refresh should be {@link WXRefreshView}
-     */
-    public void setHeaderView(WXComponent refresh) {
-        setRefreshEnable(true);
-        if (swipeLayout != null) {
-            WXRefreshView refreshView = swipeLayout.getHeaderView();
-            if (refreshView != null) {
-                if (refresh != null) {
-                    int refreshHeight = (int) refresh.getLayoutHeight();
-                    swipeLayout.setRefreshHeight(refreshHeight);
-                    String colorStr = (String) refresh.getStyles().get(Constants.Name.BACKGROUND_COLOR);
-                    String bgColor = WXUtils.getString(colorStr, null);
-                    if (bgColor != null) {
-                        if (!TextUtils.isEmpty(bgColor)) {
-                            int colorInt = WXResourceUtils.getColor(bgColor);
-                            if (!(colorInt == Color.TRANSPARENT)) {
-                                swipeLayout.setRefreshBgColor(colorInt);
-                            }
-                        }
-                    }
-                    refreshView.setRefreshView(refresh.getHostView());
-                }
-            }
-        }
-    }
-
-    /**
-     *
-     * @param loading should be {@link WXRefreshView}
-     */
-    public void setFooterView(WXComponent loading) {
-        setLoadmoreEnable(true);
-        if (swipeLayout != null) {
-            WXRefreshView refreshView = swipeLayout.getFooterView();
-            if (refreshView != null) {
-                if (loading != null) {
-                    int loadingHeight = (int) loading.getLayoutHeight();
-                    swipeLayout.setLoadingHeight(loadingHeight);
-                    String colorStr = (String) loading.getStyles().get(Constants.Name.BACKGROUND_COLOR);
-                    String bgColor = WXUtils.getString(colorStr, null);
-                    if (bgColor != null) {
-                        if (!TextUtils.isEmpty(bgColor)) {
-                            int colorInt = WXResourceUtils.getColor(bgColor);
-                            if (!(colorInt == Color.TRANSPARENT)) {
-                                swipeLayout.setLoadingBgColor(colorInt);
-                            }
-                        }
-                    }
-                    refreshView.setRefreshView(loading.getHostView());
-                }
-            }
-        }
-    }
-
-    public void removeFooterView(WXComponent loading){
-        setLoadmoreEnable(false);
-        if(swipeLayout!=null){
-            if(swipeLayout.getFooterView()!=null){
-                swipeLayout.setLoadingHeight(0);
-                swipeLayout.getFooterView().removeView(loading.getHostView());
-                swipeLayout.finishPullLoad();
-            }
-        }
-    }
-    //TODO There are bugs, will be more than a rolling height
-    public void removeHeaderView(WXComponent refresh){
-        setRefreshEnable(false);
-        if(swipeLayout!=null){
-            if(swipeLayout.getHeaderView()!=null){
-                swipeLayout.setRefreshHeight(0);
-                swipeLayout.getHeaderView().removeView(refresh.getHostView());
-                swipeLayout.finishPullRefresh();
-            }
-        }
-    }
-
-    public void setRefreshEnable(boolean enable) {
-        if (swipeLayout != null)
-            swipeLayout.setPullRefreshEnable(enable);
-    }
-
-    public void setLoadmoreEnable(boolean enable) {
-        if (swipeLayout != null)
-            swipeLayout.setPullLoadEnable(enable);
-    }
-
-    @Override
-    public void removeView(View view) {
-        if (view instanceof WXLoadingLayout) {
-            finishPullLoad();
-            setLoadmoreEnable(false);
-            if (swipeLayout != null) {
-                swipeLayout.removeView(swipeLayout.getFooterView());
-            }
-        } else if (view instanceof WXRefreshLayout) {
-            finishPullRefresh();
-            setRefreshEnable(false);
-            if (swipeLayout != null) {
-                swipeLayout.removeView(swipeLayout.getHeaderView());
-            }
-        } else {
-            super.removeView(view);
-        }
-    }
-
-    public WXSwipeLayout getSwipeLayout() {
-        return swipeLayout;
-    }
-
-    public abstract void onRefreshingComplete();
-
-    public abstract void onLoadmoreComplete();
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BounceRecyclerView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BounceRecyclerView.java
deleted file mode 100644
index 84e7ac7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BounceRecyclerView.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.refresh.wrapper;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.view.MotionEvent;
-
-import com.taobao.weex.ui.component.list.ListComponentView;
-import com.taobao.weex.ui.component.list.StickyHeaderHelper;
-import com.taobao.weex.ui.component.list.WXCell;
-import com.taobao.weex.ui.view.gesture.WXGesture;
-import com.taobao.weex.ui.view.gesture.WXGestureObservable;
-import com.taobao.weex.ui.view.listview.WXRecyclerView;
-import com.taobao.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
-
-@SuppressLint("ViewConstructor")
-public class BounceRecyclerView extends BaseBounceView<WXRecyclerView> implements ListComponentView,WXGestureObservable {
-
-  public static final int DEFAULT_COLUMN_COUNT = 1;
-  public static final int DEFAULT_COLUMN_GAP = 1;
-  private RecyclerViewBaseAdapter adapter = null;
-  private WXGesture mGesture;
-  private int mLayoutType = WXRecyclerView.TYPE_LINEAR_LAYOUT;
-  private int mColumnCount = DEFAULT_COLUMN_COUNT;
-  private float mColumnGap = DEFAULT_COLUMN_GAP;
-  private StickyHeaderHelper mStickyHeaderHelper;
-
-  public BounceRecyclerView(Context context,int type,int columnCount,float columnGap,int orientation) {
-    super(context, orientation);
-    mLayoutType = type;
-    mColumnCount = columnCount;
-    mColumnGap = columnGap;
-    init(context);
-    mStickyHeaderHelper = new StickyHeaderHelper(this);
-  }
-
-  public BounceRecyclerView(Context context,int type,int orientation) {
-    this(context,type, DEFAULT_COLUMN_COUNT, DEFAULT_COLUMN_GAP,orientation);
-  }
-
-  public void setRecyclerViewBaseAdapter(RecyclerViewBaseAdapter adapter) {
-    this.adapter = adapter;
-    if (getInnerView() != null) {
-      getInnerView().setAdapter(adapter);
-    }
-  }
-
-  public RecyclerViewBaseAdapter getRecyclerViewBaseAdapter() {
-    return adapter;
-  }
-
-  @Override
-  public boolean dispatchTouchEvent(MotionEvent event) {
-    boolean result = super.dispatchTouchEvent(event);
-    if (mGesture != null) {
-      result |= mGesture.onTouch(this, event);
-    }
-    return result;
-  }
-
-  @Override
-  public WXRecyclerView setInnerView(Context context) {
-    WXRecyclerView wxRecyclerView = new WXRecyclerView(context);
-    wxRecyclerView.initView(context, mLayoutType,mColumnCount,mColumnGap,getOrientation());
-    return wxRecyclerView;
-  }
-
-  @Override
-  public void onRefreshingComplete() {
-    if (adapter != null) {
-      adapter.notifyDataSetChanged();
-    }
-  }
-
-  @Override
-  public void onLoadmoreComplete() {
-    if (adapter != null) {
-      adapter.notifyDataSetChanged();
-    }
-  }
-
-  /**
-   * @param component
-   */
-  public void notifyStickyShow(WXCell component) {
-    mStickyHeaderHelper.notifyStickyShow(component);
-  }
-
-  @Override
-  public void updateStickyView(int currentStickyPos) {
-    mStickyHeaderHelper.updateStickyView(currentStickyPos);
-  }
-
-  /**
-   *
-   * @param compToRemove
-   */
-  @Override
-  public void notifyStickyRemove(WXCell compToRemove) {
-    mStickyHeaderHelper.notifyStickyRemove(compToRemove);
-  }
-
-  public StickyHeaderHelper getStickyHeaderHelper() {
-    return mStickyHeaderHelper;
-  }
-
-  @Override
-  public void registerGestureListener(@Nullable WXGesture wxGesture) {
-    mGesture = wxGesture;
-    getInnerView().registerGestureListener(wxGesture);
-  }
-
-  @Override
-  public WXGesture getGestureListener() {
-    return mGesture;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BounceScrollerView.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BounceScrollerView.java
deleted file mode 100644
index 20e2249..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/refresh/wrapper/BounceScrollerView.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.refresh.wrapper;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-
-import com.taobao.weex.ui.component.WXScroller;
-import com.taobao.weex.ui.view.WXScrollView;
-
-@SuppressLint("ViewConstructor")
-public class BounceScrollerView extends BaseBounceView<WXScrollView> {
-
-    public BounceScrollerView(Context context, int orientation, WXScroller waScroller) {
-        super(context,orientation);
-        init(context);
-        if (getInnerView() != null)
-            getInnerView().setWAScroller(waScroller);
-    }
-
-    @Override
-    public WXScrollView setInnerView(Context context) {
-        return new WXScrollView(context);
-    }
-
-    @Override
-    public void onRefreshingComplete() {
-        //TODO update scroller dataset
-    }
-
-    @Override
-    public void onLoadmoreComplete() {
-        //TODO update scroller dataset
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/ATagUtil.java b/android/sdk/src/main/java/com/taobao/weex/utils/ATagUtil.java
deleted file mode 100644
index cc179e3..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/ATagUtil.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.net.Uri;
-import android.view.View;
-
-import com.alibaba.fastjson.JSONArray;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.URIAdapter;
-
-public class ATagUtil {
-  public static void onClick(View widget, String instanceId, String url) {
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance == null) {
-      return;
-    }
-    String href = instance.rewriteUri(Uri.parse(url), URIAdapter.LINK).toString();
-    JSONArray array = new JSONArray();
-    array.add(href);
-    WXSDKManager.getInstance().getWXBridgeManager().
-        callModuleMethod(instanceId, "event", "openURL", array);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/BoxShadowUtil.java b/android/sdk/src/main/java/com/taobao/weex/utils/BoxShadowUtil.java
deleted file mode 100644
index 66df2c9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/BoxShadowUtil.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
-import android.graphics.Shader;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Build;
-import android.os.Build.VERSION_CODES;
-import android.support.annotation.IntRange;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.common.WXThread;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Created by moxun on 2017/9/4.
- * Utils for create shadow layer on view
- * Requires Android 4.3 and higher
- *
- * @see <a href="https://www.w3schools.com/cssref/css3_pr_box-shadow.asp">CSS3 box-shadow Property</>
- */
-
-public class BoxShadowUtil {
-  private static final String TAG = "BoxShadowUtil";
-  private static boolean sBoxShadowEnabled = true /*disable box-shadow temporary*/;
-
-  private static Pattern sColorPattern;
-
-  public static void setBoxShadowEnabled(boolean enabled) {
-    sBoxShadowEnabled = enabled;
-    WXLogUtils.w(TAG, "Switch box-shadow status: " + enabled);
-  }
-
-  public static boolean isBoxShadowEnabled() {
-    return sBoxShadowEnabled;
-  }
-
-  public static void setBoxShadow(final View target, String style, final float[] radii, int viewPort, final float quality) {
-    if (!sBoxShadowEnabled) {
-      WXLogUtils.w(TAG, "box-shadow was disabled by config");
-      return;
-    }
-
-    if (target == null) {
-      WXLogUtils.w(TAG, "Target view is null!");
-      return;
-    }
-
-    if (TextUtils.isEmpty(style) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-      target.getOverlay().clear();
-      WXLogUtils.d(TAG, "Remove all box-shadow");
-      return;
-    }
-
-    final BoxShadowOptions[] shadows = parseBoxShadows(style, viewPort);
-    if (shadows == null || shadows.length == 0) {
-      WXLogUtils.w(TAG, "Failed to parse box-shadow: " + style);
-      return;
-    }
-
-    final List<BoxShadowOptions> normalShadows = new ArrayList<>(), insetShadows = new ArrayList<>();
-    for (BoxShadowOptions shadow : shadows) {
-      if (shadow != null) {
-        if (shadow.isInset) {
-          insetShadows.add(0, shadow);
-        } else {
-          normalShadows.add(0, shadow);
-        }
-      }
-    }
-
-    if (radii != null) {
-      if (radii.length != 8) {
-        WXLogUtils.w(TAG, "Length of radii must be 8");
-      } else {
-        for (int i = 0; i < radii.length; i++) {
-          float realRadius = WXViewUtils.getRealSubPxByWidth(radii[i], viewPort);
-          radii[i] = realRadius;
-        }
-      }
-    }
-
-    target.post(WXThread.secure(new Runnable() {
-      @Override
-      public void run() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-          target.getOverlay().clear();
-          if (normalShadows.size() > 0) {
-            setNormalBoxShadow(target, normalShadows, quality, radii);
-          }
-
-          if (insetShadows.size() > 0) {
-            setInsetBoxShadow(target, insetShadows, quality, radii);
-          }
-        }
-      }
-    }));
-  }
-
-  private static void drawShadow(Canvas canvas, BoxShadowOptions options) {
-    RectF shadowRect = new RectF(
-        0f, 0f,
-        options.viewWidth + 2f * options.spread, options.viewHeight + 2f * options.spread
-    );
-
-    if (options.topLeft != null) {
-      shadowRect.offset(options.topLeft.x, options.topLeft.y);
-    }
-
-    float shadowDx = options.blur;
-    float shadowDy = options.blur;
-    if (options.hShadow > 0) {
-      shadowDx = shadowDx + 2f * options.hShadow;
-    }
-    if (options.vShadow > 0) {
-      shadowDy = shadowDy + 2f * options.vShadow;
-    }
-    shadowRect.offset(shadowDx, shadowDy);
-
-    Paint shadowPaint = new Paint();
-    shadowPaint.setAntiAlias(true);
-    shadowPaint.setColor(options.color);
-    shadowPaint.setStyle(Paint.Style.FILL);
-
-    if (options.blur > 0) {
-      shadowPaint.setMaskFilter(new BlurMaskFilter(options.blur, BlurMaskFilter.Blur.NORMAL));
-    }
-
-    Path shadowPath = new Path();
-    float[] shadowRadii = new float[8];
-    for (int i = 0; i < options.radii.length; i++) {
-      float contentRadius = options.radii[i];
-      if (contentRadius == 0f) {
-        shadowRadii[i] = 0f;
-      } else {
-        shadowRadii[i] = options.radii[i] + options.spread;
-      }
-    }
-    shadowPath.addRoundRect(shadowRect, shadowRadii, Path.Direction.CCW);
-    canvas.drawPath(shadowPath, shadowPaint);
-
-    if (false && WXEnvironment.isApkDebugable()) {
-      Paint paint = new Paint();
-      paint.setAntiAlias(true);
-      paint.setColor(Color.BLACK);
-      paint.setStyle(Paint.Style.STROKE);
-      canvas.drawRect(shadowRect, paint);
-    }
-  }
-
-  private static void setNormalBoxShadow(View target, List<BoxShadowOptions> options, float quality, float[] radii) {
-    int h = target.getHeight();
-    int w = target.getWidth();
-
-    ViewGroup.LayoutParams p = target.getLayoutParams();
-
-    if (h == 0 || w == 0) {
-      Log.w(TAG, "Target view is invisible, ignore set shadow.");
-      return;
-    }
-
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-      int maxWidth = 0, maxHeight = 0;
-      for (BoxShadowOptions option : options) {
-        option.viewWidth = w;
-        option.viewHeight = h;
-        option.radii = radii;
-
-        Rect rect = option.getTargetCanvasRect();
-        if (maxWidth < rect.width()) {
-          maxWidth = rect.width();
-        }
-
-        if (maxHeight < rect.height()) {
-          maxHeight = rect.height();
-        }
-      }
-
-      int canvasWidth = (int) (maxWidth * quality);
-      int canvasHeight = (int) (maxHeight * quality);
-      Bitmap output = Bitmap.createBitmap(canvasWidth, canvasHeight, Bitmap.Config.ARGB_4444);
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-        WXLogUtils.d(TAG, "Allocation memory for box-shadow: " + (output.getAllocationByteCount() / 1024) + " KB");
-      }
-      Canvas canvas = new Canvas(output);
-
-      if (false && WXEnvironment.isApkDebugable()) {
-        // Using for debug
-        Paint strokePaint = new Paint();
-        strokePaint.setColor(Color.BLACK);
-        strokePaint.setStrokeWidth(2);
-        strokePaint.setStyle(Paint.Style.STROKE);
-        canvas.drawRect(canvas.getClipBounds(), strokePaint);
-      }
-
-      for (BoxShadowOptions option : options) {
-        Rect rect = option.getTargetCanvasRect();
-        float left = (maxWidth - rect.width()) / 2f;
-        float top = (maxHeight - rect.height()) / 2f;
-        option.topLeft = new PointF(left, top);
-
-        BoxShadowOptions scaledOption = option.scale(quality);
-        drawShadow(canvas, scaledOption);
-      }
-
-      //Drawable's bounds must match the bitmap size, otherwise the shadows will be scaled
-      int paddingX = (maxWidth - w) / 2;
-      int paddingY = (maxHeight - h) / 2;
-      OverflowBitmapDrawable shadowDrawable = new OverflowBitmapDrawable(target.getResources(),
-          output, new Point(paddingX, paddingY), new Rect(0, 0, w, h), radii);
-
-      target.getOverlay().add(shadowDrawable);
-      //Relayout to ensure the shadows are fully drawn
-      ViewParent parent = target.getParent();
-      if (parent != null) {
-        parent.requestLayout();
-        if (parent instanceof ViewGroup) {
-          ((ViewGroup) parent).invalidate(shadowDrawable.getBounds());
-        }
-      }
-    } else {
-      // I have a dream that one day our minSdkVersion will equals or higher than 21
-      Log.w("BoxShadowUtil", "Call setNormalBoxShadow() requires API level 18 or higher.");
-    }
-  }
-
-  private static void setInsetBoxShadow(View target, List<BoxShadowOptions> options, float quality, float[] radii) {
-    if (target == null || options == null) {
-      WXLogUtils.w(TAG, "Illegal arguments");
-      return;
-    }
-
-    if (target.getWidth() == 0 || target.getHeight() == 0) {
-      WXLogUtils.w(TAG, "Target view is invisible, ignore set shadow.");
-      return;
-    }
-
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-      Drawable[] drawables = new Drawable[options.size()];
-      for (int i = 0; i < options.size(); i++) {
-        BoxShadowOptions option = options.get(i);
-        Drawable shadow = new InsetShadowDrawable(target.getWidth(), target.getHeight(),
-            option.hShadow, option.vShadow,
-            option.blur, option.spread,
-            option.color, radii);
-        drawables[i] = shadow;
-      }
-
-      LayerDrawable layerDrawable = new LayerDrawable(drawables);
-      target.getOverlay().add(layerDrawable);
-      target.invalidate();
-    } else {
-      Log.w(TAG, "Call setInsetBoxShadow() requires API level 18 or higher.");
-    }
-  }
-
-  public static BoxShadowOptions[] parseBoxShadows(String boxShadowStyle, int viewport) {
-    // normalization color expression to #AARRGGBB
-    if (sColorPattern == null) {
-      sColorPattern = Pattern.compile("([rR][gG][bB][aA]?)\\((\\d+\\s*),\\s*(\\d+\\s*),\\s*(\\d+\\s*)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)");
-    }
-
-    Matcher matcher = sColorPattern.matcher(boxShadowStyle);
-
-    String processedStyle = boxShadowStyle;
-    while (matcher.find()) {
-      String color = matcher.group();
-      processedStyle = processedStyle.replace(color, "#" + String.format("%8s", Integer.toHexString(WXResourceUtils.getColor(color, Color.BLACK))).replaceAll("\\s", "0"));
-    }
-
-    String[] styles = processedStyle.split(",");
-    if (styles != null && styles.length > 0) {
-      BoxShadowOptions[] result = new BoxShadowOptions[styles.length];
-      for (int i = 0; i < styles.length; i++) {
-        result[i] = parseBoxShadow(styles[i], viewport);
-      }
-      return result;
-    }
-    return null;
-  }
-
-  private static BoxShadowOptions parseBoxShadow(String boxShadow, int viewport) {
-    BoxShadowOptions result = new BoxShadowOptions(viewport);
-    if (TextUtils.isEmpty(boxShadow)) {
-      return null;
-    }
-
-    String boxShadowCopy = boxShadow;
-
-    // trim rgb() & rgba()
-    boxShadowCopy = boxShadowCopy.replaceAll("\\s*,\\s+", ",");
-
-    // match inset first
-    if (boxShadowCopy.contains("inset")) {
-      result.isInset = true;
-      boxShadowCopy = boxShadowCopy.replace("inset", "");
-    }
-
-    boxShadowCopy = boxShadowCopy.trim();
-    List<String> params = new ArrayList<>(Arrays.asList(boxShadowCopy.split("\\s+")));
-
-    // match color
-    String maybeColor = params.get(params.size() - 1);
-    if (!TextUtils.isEmpty(maybeColor)) {
-      if (maybeColor.startsWith("#") || maybeColor.startsWith("rgb") || WXResourceUtils.isNamedColor(maybeColor)) {
-        result.color = WXResourceUtils.getColor(maybeColor, Color.BLACK);
-        params.remove(params.size() - 1);
-      }
-    }
-
-    try {
-      if (params.size() < 2) {
-        // Missing required param
-        return null;
-      } else {
-        if (!TextUtils.isEmpty(params.get(0))) {
-          float px = WXUtils.getFloat(params.get(0).trim(), 0f);
-          result.hShadow = WXViewUtils.getRealSubPxByWidth(px, viewport);
-        }
-
-        if (!TextUtils.isEmpty(params.get(1))) {
-          float px = WXUtils.getFloat(params.get(1).trim(), 0f);
-          result.vShadow = WXViewUtils.getRealPxByWidth(px, viewport);
-        }
-
-        for (int i = 2; i < params.size(); i++) {
-          int parserIndex = i - 2;
-          BoxShadowOptions.IParser parser = result.optionParamParsers.get(parserIndex);
-          parser.parse(params.get(i));
-        }
-      }
-    } catch (Throwable t) {
-      t.printStackTrace();
-    }
-    return result;
-  }
-
-  private static class OverflowBitmapDrawable extends BitmapDrawable {
-    private int paddingX;
-    private int paddingY;
-    private Rect viewRect;
-    private float[] radii;
-
-    private OverflowBitmapDrawable(Resources resources, Bitmap bitmap, Point topLeft, Rect viewRect, float[] radii) {
-      super(resources, bitmap);
-      this.paddingX = topLeft.x;
-      this.paddingY = topLeft.y;
-      this.viewRect = viewRect;
-      this.radii = radii;
-
-      setBounds(-paddingX, -paddingY, viewRect.width() + paddingX, viewRect.height() + paddingY);
-    }
-
-    public void draw(Canvas canvas) {
-      Rect bounds = canvas.getClipBounds();
-      Rect newRect = new Rect(bounds);
-      // Make the Canvas Rect bigger according to the padding.
-      newRect.inset(-paddingX * 2, -paddingY * 2);
-      try {
-        if(WXEnvironment.sApplication.getApplicationInfo().targetSdkVersion > VERSION_CODES.O){
-          canvas.clipRect(newRect);
-        }
-        else{
-          canvas.clipRect(newRect, Region.Op.REPLACE);
-        }
-      }catch (NullPointerException e) {
-        canvas.clipRect(newRect);
-      }
-
-      Path contentPath = new Path();
-      // the content area map must be aligned with bounds
-      RectF rectF = new RectF(bounds);
-      contentPath.addRoundRect(rectF, radii, Path.Direction.CCW);
-      // can not antialias
-      canvas.clipPath(contentPath, Region.Op.DIFFERENCE);
-
-      // translate the canvas to a suitable position and then draw the bitmap, otherwise draw from the origin(0, 0)
-      canvas.translate(bounds.left, bounds.top);
-
-      super.draw(canvas);
-    }
-  }
-
-  private static class InsetShadowDrawable extends Drawable {
-    private static final int LEFT_TO_RIGHT = 0;
-    private static final int TOP_TO_BOTTOM = 1;
-    private static final int RIGHT_TO_LEFT = 2;
-    private static final int BOTTOM_TO_TOP = 3;
-
-    private float blurRadius;
-    private int shadowColor;
-
-    private float[] radii;
-
-    private float width, height;
-
-    private float shadowXSize, shadowYSize;
-
-    private Shader[] shades = new Shader[4];
-    private Path[] paths = new Path[4];
-
-    private Paint paint;
-
-    private InsetShadowDrawable(int viewWidth, int viewHeight, float dx, float dy, float blurRadius, float spread, int shadowColor, float[] radii) {
-      this.blurRadius = blurRadius;
-      this.shadowColor = shadowColor;
-
-      this.width = viewWidth + 2 * dx;
-      this.height = viewHeight + 2 * dy;
-
-      this.shadowXSize = dx + spread;
-      this.shadowYSize = dy + spread;
-
-      this.radii = radii;
-
-      setBounds(0, 0, viewWidth, viewHeight);
-      prepare();
-    }
-
-    private void prepare() {
-      /*
-       *  A +++++++++++++++++++++++++ B
-       *  +  E ------------------- F  +
-       *  +  |                     |  +
-       *  +  |                     |  +
-       *  +  |                     |  +
-       *  +  H ------------------- G  +
-       *  D +++++++++++++++++++++++++ C
-       */
-
-      PointF a = new PointF(0, 0);
-      PointF b = new PointF(width, 0);
-      PointF c = new PointF(b.x, height);
-      PointF d = new PointF(a.x, c.y);
-
-      PointF e = new PointF(shadowXSize, shadowYSize);
-      PointF f = new PointF(b.x - shadowXSize, e.y);
-      PointF g = new PointF(f.x, c.y - shadowYSize);
-      PointF h = new PointF(e.x, g.y);
-
-      Shader ltr = new LinearGradient(e.x - blurRadius, e.y, e.x, e.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
-      Shader ttb = new LinearGradient(e.x, e.y - blurRadius, e.x, e.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
-      Shader rtl = new LinearGradient(g.x + blurRadius, g.y, g.x, g.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
-      Shader btt = new LinearGradient(g.x, g.y + blurRadius, g.x, g.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
-
-      shades[LEFT_TO_RIGHT] = ltr;
-      shades[TOP_TO_BOTTOM] = ttb;
-      shades[RIGHT_TO_LEFT] = rtl;
-      shades[BOTTOM_TO_TOP] = btt;
-
-      Path ltrPath = new Path();
-      ltrPath.moveTo(a.x, a.y);
-      ltrPath.lineTo(e.x, e.y);
-      ltrPath.lineTo(h.x, h.y);
-      ltrPath.lineTo(d.x, d.y);
-      ltrPath.close();
-
-      Path ttbPath = new Path();
-      ttbPath.moveTo(a.x, a.y);
-      ttbPath.lineTo(b.x, b.y);
-      ttbPath.lineTo(f.x, f.y);
-      ttbPath.lineTo(e.x, e.y);
-      ttbPath.close();
-
-      Path rtlPath = new Path();
-      rtlPath.moveTo(b.x, b.y);
-      rtlPath.lineTo(c.x, c.y);
-      rtlPath.lineTo(g.x, g.y);
-      rtlPath.lineTo(f.x, f.y);
-      rtlPath.close();
-
-      Path bttPath = new Path();
-      bttPath.moveTo(d.x, d.y);
-      bttPath.lineTo(c.x, c.y);
-      bttPath.lineTo(g.x, g.y);
-      bttPath.lineTo(h.x, h.y);
-      bttPath.close();
-
-      paths[LEFT_TO_RIGHT] = ltrPath;
-      paths[TOP_TO_BOTTOM] = ttbPath;
-      paths[RIGHT_TO_LEFT] = rtlPath;
-      paths[BOTTOM_TO_TOP] = bttPath;
-
-      paint = new Paint();
-      paint.setAntiAlias(true);
-      paint.setStyle(Paint.Style.FILL);
-      paint.setColor(shadowColor);
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-      Rect bounds = canvas.getClipBounds();
-      Path border = new Path();
-      RectF rectF = new RectF(bounds);
-      border.addRoundRect(rectF, radii, Path.Direction.CCW);
-      canvas.clipPath(border);
-      //TODO: we need clip border-width too
-
-      // translate the canvas to the right place and then draw the inner shadow
-      canvas.translate(bounds.left, bounds.top);
-
-      for (int i = 0; i < 4; i++) {
-        Shader shader = shades[i];
-        Path path = paths[i];
-        paint.setShader(shader);
-        canvas.drawPath(path, paint);
-      }
-    }
-
-    @Override
-    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
-
-    }
-
-    @Override
-    public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
-    }
-
-    @Override
-    public int getOpacity() {
-      return PixelFormat.OPAQUE;
-    }
-  }
-
-  public static class BoxShadowOptions {
-    private List<IParser> optionParamParsers;
-    private int viewport = 750;
-
-    public float hShadow;
-    public float vShadow;
-    public float blur = 0f;
-    public float spread = 0f;
-    public float[] radii = new float[]{0, 0, 0, 0, 0, 0, 0, 0};
-    public int color = Color.BLACK;
-    public boolean isInset = false;
-
-    public int viewWidth = 0;
-    public int viewHeight = 0;
-    public PointF topLeft = null;
-
-    private BoxShadowOptions(int vp) {
-      if (viewport != 0) {
-        this.viewport = vp;
-      }
-      optionParamParsers = new ArrayList<>();
-
-      IParser spreadParser = new IParser() {
-        @Override
-        public void parse(String param) {
-          if (!TextUtils.isEmpty(param)) {
-            float px = WXUtils.getFloat(param, 0f);
-            spread = WXViewUtils.getRealSubPxByWidth(px, viewport);
-            WXLogUtils.w(TAG, "Experimental box-shadow attribute: spread");
-          }
-        }
-      };
-
-      IParser blurParser = new IParser() {
-        @Override
-        public void parse(String param) {
-          if (!TextUtils.isEmpty(param)) {
-            float px = WXUtils.getFloat(param, 0f);
-            blur = WXViewUtils.getRealSubPxByWidth(px, viewport);
-          }
-        }
-      };
-
-      optionParamParsers.add(blurParser);
-      optionParamParsers.add(spreadParser);
-    }
-
-    public BoxShadowOptions scale(float scale) {
-      if (scale > 0f && scale <= 1f) {
-        BoxShadowOptions scaledOptions = new BoxShadowOptions(viewport);
-        scaledOptions.hShadow = hShadow * scale;
-        scaledOptions.vShadow = vShadow * scale;
-        scaledOptions.blur = blur * scale;
-        scaledOptions.spread = spread * scale;
-        for (int i = 0; i < radii.length ; i++) {
-          scaledOptions.radii[i] = radii[i] * scale;
-        }
-        scaledOptions.viewHeight = (int) (viewHeight * scale);
-        scaledOptions.viewWidth = (int) (viewWidth * scale);
-
-        if (topLeft != null) {
-          scaledOptions.topLeft = new PointF();
-          scaledOptions.topLeft.x = topLeft.x * scale;
-          scaledOptions.topLeft.y = topLeft.y * scale;
-        }
-
-        scaledOptions.color = color;
-        scaledOptions.isInset = isInset;
-        WXLogUtils.d(TAG, "Scaled BoxShadowOptions: [" + scale + "] " + scaledOptions);
-        return scaledOptions;
-      }
-      return null;
-    }
-
-    public Rect getTargetCanvasRect() {
-      int canvasWidth = viewWidth + 2 * (int) (blur + spread + Math.abs(hShadow));
-      int canvasHeight = viewHeight + 2 * (int) (blur + spread + Math.abs(vShadow));
-      return new Rect(0, 0, canvasWidth, canvasHeight);
-    }
-
-    @Override
-    public String toString() {
-
-      String r = "[" + radii[0] + "," + radii[2] + "," + radii[4] + "," + radii[6] + "]";
-
-      final StringBuffer sb = new StringBuffer("BoxShadowOptions{");
-      sb.append("h-shadow=").append(hShadow);
-      sb.append(", v-shadow=").append(vShadow);
-      sb.append(", blur=").append(blur);
-      sb.append(", spread=").append(spread);
-      sb.append(", corner-radius=").append(r);
-      sb.append(", color=#").append(Integer.toHexString(color));
-      sb.append(", inset=").append(isInset);
-      sb.append('}');
-      return sb.toString();
-    }
-
-    private interface IParser {
-      void parse(String param);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/FontDO.java b/android/sdk/src/main/java/com/taobao/weex/utils/FontDO.java
deleted file mode 100644
index a79ade0..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/FontDO.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.graphics.Typeface;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Base64;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.adapter.URIAdapter;
-import com.taobao.weex.common.Constants;
-import java.io.File;
-
-public class FontDO {
-  private final String mFontFamilyName;
-  private String mUrl = "";
-  private String mFilePath;
-  private int mType = TYPE_NETWORK;
-  private Typeface mTypeface;
-  private int mState = STATE_INVALID;
-
-  public final static int STATE_INVALID = -1;
-  public final static int STATE_INIT = 0;
-  public final static int STATE_LOADING = 1;
-  public final static int STATE_SUCCESS = 2;
-  public final static int STATE_FAILED = 3;
-
-  public final static int TYPE_UNKNOWN = 0;
-  public final static int TYPE_NETWORK = 1;
-  public final static int TYPE_FILE = 2;
-  public final static int TYPE_LOCAL = 3;
-  public final static int TYPE_NATIVE = 4;
-  public final static int TYPE_BASE64 = 5;
-
-
-  public FontDO (String fontFamilyName, String src, WXSDKInstance instance) {
-    this.mFontFamilyName = fontFamilyName;
-    parseSrc(src,instance);
-  }
-
-  public FontDO (String fontFamilyName, Typeface typeface) {
-    this.mFontFamilyName = fontFamilyName;
-    this.mTypeface = typeface;
-    this.mType = TYPE_NATIVE;
-    this.mState = STATE_SUCCESS;
-  }
-
-  public String getFontFamilyName() {
-    return mFontFamilyName;
-  }
-
-  private void parseSrc(String src, WXSDKInstance instance) {
-    src = (src != null )? src.trim() : "";
-
-    if (instance != null) {
-      if (instance.getCustomFontNetworkHandler() != null) {
-        String localUrl = instance.getCustomFontNetworkHandler().fetchLocal(src);
-        if (!TextUtils.isEmpty(localUrl)) {
-          src = localUrl;
-        }
-      }
-    }
-
-    if (src.isEmpty()) {
-      mState = STATE_INVALID;
-      WXLogUtils.e("TypefaceUtil", "font src is empty.");
-      return;
-    }
-
-    if (src.matches("^url\\((('.*')|(\".*\"))\\)$")) {
-      String url = src.substring(5, src.length() - 2);
-      Uri uri = Uri.parse(url);
-      if( instance != null){
-        uri = instance.rewriteUri(uri,URIAdapter.FONT);
-      }
-      mUrl = uri.toString();
-      try {
-        String scheme = uri.getScheme();
-        if (Constants.Scheme.HTTP.equals(scheme) ||
-                Constants.Scheme.HTTPS.equals(scheme)) {
-          mType = TYPE_NETWORK;
-        } else if (Constants.Scheme.FILE.equals(scheme)) {
-          mType = TYPE_FILE;
-            /**
-             * eg: file://name/A/B.ttf
-             * getPath() = "A/B.ttf",but the real absolute path is "/name/A/B.ttf"
-             * so use getEncodedSchemeSpecificPart() to replaced = "//name/A/B.ttf"
-             */
-            mUrl = uri.getEncodedSchemeSpecificPart();
-        } else if (Constants.Scheme.LOCAL.equals(scheme)){
-          mType = TYPE_LOCAL;
-        } else if (Constants.Scheme.DATA.equals(scheme)) {
-          long start = System.currentTimeMillis();
-          String[] data = mUrl.split(",");
-          if (data != null && data.length == 2) {
-            String identify = data[0];
-            if (!TextUtils.isEmpty(identify) && identify.endsWith("base64")) {
-              //Do not check mime type and charset for now
-              String base64Data = data[1];
-              if (!TextUtils.isEmpty(base64Data)) {
-                String md5 = WXFileUtils.md5(base64Data);
-                File cacheDir = new File(WXEnvironment.getApplication().getCacheDir(),
-                    "font-family");
-                if (!cacheDir.exists()) {
-                  cacheDir.mkdirs();
-                }
-                File tmpFile = new File(cacheDir, md5);
-                if(!tmpFile.exists()){
-                  tmpFile.createNewFile();
-                  WXFileUtils.saveFile(tmpFile.getPath(), Base64.decode(base64Data, Base64.DEFAULT), WXEnvironment.getApplication());
-                }
-                mUrl = tmpFile.getPath();
-                mType = TYPE_BASE64;
-                WXLogUtils.d("TypefaceUtil", "Parse base64 font cost " + (System.currentTimeMillis() - start) + " ms");
-              }
-            }
-          }
-        } else {
-          WXLogUtils.e("TypefaceUtil", "Unknown scheme for font url: " + mUrl);
-          mType = TYPE_UNKNOWN;
-        }
-        mState = STATE_INIT;
-      } catch (Exception e) {
-        mType = STATE_INVALID;
-        WXLogUtils.e("TypefaceUtil", "URI.create(mUrl) failed mUrl: " + mUrl+ "\n"+ WXLogUtils.getStackTrace(e));
-      }
-    } else {
-      mUrl = src;
-      mState = STATE_INVALID;
-    }
-
-    if(WXEnvironment.isApkDebugable()) {
-      WXLogUtils.d("TypefaceUtil", "src:" + src + ", mUrl:" + mUrl + ", mType:" + mType);
-    }
-  }
-
-  public String getUrl() {
-    return mUrl;
-  }
-
-  public int getType() {
-    return mType;
-  }
-
-  public Typeface getTypeface() {
-    return mTypeface;
-  }
-
-  public void setTypeface(Typeface typeface) {
-    this.mTypeface = typeface;
-  }
-
-  public int getState() {
-    return mState;
-  }
-
-  public void setState(int state) {
-    this.mState = state;
-  }
-
-  public String getFilePath() {
-    return mFilePath;
-  }
-
-  public void setFilePath(String mFilePath) {
-    this.mFilePath = mFilePath;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/FunctionParser.java b/android/sdk/src/main/java/com/taobao/weex/utils/FunctionParser.java
deleted file mode 100644
index 93ace90..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/FunctionParser.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.support.annotation.NonNull;
-
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Parser for function like "rotate(30 ) transform(50 , 20)".
- * This class will translate the raw string presentation of a group of function(s) to give type
- * according to the {@link com.taobao.weex.utils.FunctionParser.Mapper}
- */
-public class FunctionParser<K, V> {
-
-  public static final char SPACE = ' ';
-
-  private Mapper<K, V> mapper;
-  private Lexer lexer;
-
-  /**
-   * Construct a function parser
-   * @param source the raw string representation of a group of function(s)
-   * @param mapper the mapping rule between string and corresponding type of object.
-   */
-  public FunctionParser(@NonNull String source, @NonNull Mapper<K, V> mapper) {
-    this.lexer = new Lexer(source);
-    this.mapper = mapper;
-  }
-
-  /**
-   * Start to parse the raw string. The result will be stored in a sorted map where the order
-   * is defined by the function order in the raw string.
-   * @return
-   */
-  public LinkedHashMap<K, V> parse() {
-    lexer.moveOn();
-    return definition();
-  }
-
-  private LinkedHashMap<K, V> definition() {
-    LinkedHashMap<K, V> result = new LinkedHashMap<>();
-    do {
-      result.putAll(function());
-    } while (lexer.getCurrentToken() == Token.FUNC_NAME);
-    return result;
-  }
-
-  private Map<K, V> function() {
-    List<String> list = new LinkedList<>();
-    String functionName = match(Token.FUNC_NAME);
-    match(Token.LEFT_PARENT);
-    list.add(match(Token.PARAM_VALUE));
-    while (lexer.getCurrentToken() == Token.COMMA) {
-      match(Token.COMMA);
-      list.add(match(Token.PARAM_VALUE));
-    }
-    match(Token.RIGHT_PARENT);
-    return mapper.map(functionName, list);
-  }
-
-  private String match(Token token) {
-    try {
-      if (token == lexer.getCurrentToken()) {
-        String value = lexer.getCurrentTokenValue();
-        lexer.moveOn();
-        return value;
-      }
-    } catch (Exception e) {
-      WXLogUtils.e(token + "Token doesn't match" + lexer.source);
-    }
-    return "";
-  }
-
-  private enum Token {
-    FUNC_NAME, PARAM_VALUE, LEFT_PARENT, RIGHT_PARENT, COMMA
-  }
-
-  public interface Mapper<K, V> {
-
-    /**
-     * Map one function to a specified type of object
-     * @param functionName the name of the raw function.
-     * @param raw the list of parameter of the raw function
-     * @return the expected mapping relationship, where the key in the map is the same as the
-     * key in the return value of {{@link #parse()}},
-     * and the value in the map is the type of object that expected by user.
-     */
-    Map<K, V> map(String functionName, List<String> raw);
-  }
-
-  private static class WXInterpretationException extends RuntimeException {
-
-    private WXInterpretationException(String msg) {
-      super(msg);
-    }
-  }
-
-  /**
-   * Lexer for the parser. For now,  digit, alphabet, '(', ')', '.', ',', '+', '-' and '%' is
-   * valid character, and '(', ')', ',', parameter value and function name is valid token.
-   * Parameter value is defined as "(?i)[\+-]?[0-9]+(\.[0-9]+)?(%||deg||px)?" while function
-   * name is defined as "[a-zA-Z]+".
-   *
-   * The Lexer can also be expressed using the following EBNF format.
-   * <ul>
-   *   <li>definition = {function};</li>
-   *   <li>function = name, "(", value, { ",", value } , ")";</li>
-   *   <li>name = character, {character};</li>
-   *   <li>value = identifier, {identifier};</li>
-   *   <li>identifier = character | "." | "%" | "+" | "-";</li>
-   *   <li>character = digit | letter;</li>
-   *   <li>digit =  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;</li>
-   *   <li>letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" |
-   *   "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" |
-   *   "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" |
-   *   "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" ;</li>
-   * </ul>
-   */
-  private static class Lexer {
-
-    private static final String LEFT_PARENT = "(";
-    private static final String RIGHT_PARENT = ")";
-    private static final String COMMA = ",";
-    private static final char A_LOWER = 'a';
-    private static final char Z_LOWER = 'z';
-    private static final char A_UPPER = 'A';
-    private static final char Z_UPPER = 'Z';
-    private static final char ZERO = '0';
-    private static final char NINE = '9';
-    private static final char DOT = '.';
-    private static final char MINUS = '-';
-    private static final char PLUS = '+';
-    private String source;
-    private Token current;
-    private String value;
-    private int pointer = 0;
-
-    private Lexer(String source) {
-      this.source = source;
-    }
-
-    private Token getCurrentToken() {
-      return current;
-    }
-
-    private String getCurrentTokenValue() {
-      return value;
-    }
-
-    private boolean moveOn() {
-      int start = pointer;
-      char curChar;
-      while (pointer < source.length()) {
-        curChar = source.charAt(pointer);
-        if (curChar == SPACE) {
-          if (start == pointer++) {
-            start++;
-          } else {
-            break;
-          }
-        } else if (isCharacterOrDigit(curChar) || curChar == DOT
-                || curChar == WXUtils.PERCENT || curChar == MINUS || curChar == PLUS) {
-          pointer++;
-        } else {
-          if (start == pointer) {
-            pointer++;
-          }
-          break;
-        }
-      }
-      if (start != pointer) {
-        String symbol = source.substring(start, pointer);
-        moveOn(symbol);
-        return true;
-      } else {
-        current = null;
-        value = null;
-        return false;
-      }
-    }
-
-    private void moveOn(String token) {
-      if (LEFT_PARENT.equals(token)) {
-        current = Token.LEFT_PARENT;
-        value = LEFT_PARENT;
-      } else if (RIGHT_PARENT.equals(token)) {
-        current = Token.RIGHT_PARENT;
-        value = RIGHT_PARENT;
-      } else if (COMMA.equals(token)) {
-        current = Token.COMMA;
-        value = COMMA;
-      } else if (isFuncName(token)) {
-        current = Token.FUNC_NAME;
-        value = token;
-      } else {
-        current = Token.PARAM_VALUE;
-        value = token;
-      }
-    }
-
-    private boolean isFuncName(CharSequence funcName) {
-      char letter;
-      for (int i = 0; i < funcName.length(); i++) {
-        letter = funcName.charAt(i);
-        if (!((A_LOWER <= letter && letter <= Z_LOWER) ||
-                (A_UPPER <= letter && letter <= Z_UPPER) ||
-                letter == MINUS)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    private boolean isCharacterOrDigit(char letter) {
-      return (ZERO <= letter && letter <= NINE) || (A_LOWER <= letter && letter <= Z_LOWER) ||
-              (A_UPPER <= letter && letter <= Z_UPPER);
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/ImageDrawable.java b/android/sdk/src/main/java/com/taobao/weex/utils/ImageDrawable.java
deleted file mode 100644
index f6f1010..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/ImageDrawable.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
-import android.graphics.drawable.shapes.Shape;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.widget.ImageView;
-
-public class ImageDrawable extends PaintDrawable {
-
-  public static Drawable createImageDrawable(@Nullable Drawable original,
-                                             @NonNull ImageView.ScaleType scaleType,
-                                             @Nullable float[] borderRadius,
-                                             int vWidth,
-                                             int vHeight,
-                                             boolean gif) {
-    Bitmap bm;
-    if (!gif && vWidth > 0 && vHeight > 0) {
-      if (original instanceof BitmapDrawable &&
-              (bm = ((BitmapDrawable) original).getBitmap()) != null) {
-        ImageDrawable imageDrawable;
-        imageDrawable = new ImageDrawable();
-        // fix android 9 image antialiasing
-        imageDrawable.getPaint().setFilterBitmap(true);
-        imageDrawable.bitmapWidth = bm.getWidth();
-        imageDrawable.bitmapHeight = bm.getHeight();
-        BitmapShader bitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-        updateShaderAndSize(scaleType, vWidth, vHeight, imageDrawable, bitmapShader);
-        imageDrawable.getPaint().setShader(bitmapShader);
-        return imageDrawable;
-      } else if (original instanceof ImageDrawable) {
-        ImageDrawable imageDrawable = (ImageDrawable) original;
-        if (imageDrawable.getPaint() != null &&
-                imageDrawable.getPaint().getShader() instanceof BitmapShader) {
-          BitmapShader bitmapShader = (BitmapShader) imageDrawable.getPaint().getShader();
-          updateShaderAndSize(scaleType, vWidth, vHeight, imageDrawable, bitmapShader);
-          return imageDrawable;
-        }
-      }
-    }
-    return original;
-  }
-
-  private static void updateShaderAndSize(@NonNull ImageView.ScaleType scaleType, int vWidth, int vHeight, ImageDrawable imageDrawable, BitmapShader bitmapShader) {
-    Matrix matrix = createShaderMatrix(scaleType, vWidth, vHeight,
-            imageDrawable.bitmapWidth,
-            imageDrawable.bitmapHeight);
-    int intrinsicWidth = vWidth, intrinsicHeight = vHeight;
-    if (scaleType == ImageView.ScaleType.FIT_CENTER) {
-      RectF bitmapRect = new RectF(0, 0, imageDrawable.bitmapWidth, imageDrawable.bitmapHeight), contentRect = new RectF();
-      matrix.mapRect(contentRect, bitmapRect);
-      intrinsicWidth = (int) contentRect.width();
-      intrinsicHeight = (int) contentRect.height();
-      matrix = createShaderMatrix(scaleType, intrinsicWidth, intrinsicHeight, imageDrawable
-              .bitmapWidth, imageDrawable.bitmapHeight);
-    }
-    imageDrawable.setIntrinsicWidth(intrinsicWidth);
-    imageDrawable.setIntrinsicHeight(intrinsicHeight);
-    bitmapShader.setLocalMatrix(matrix);
-  }
-
-  @NonNull
-  private static Matrix createShaderMatrix(@NonNull ImageView.ScaleType scaleType, int vWidth,
-                                           int vHeight, int bmWidth, int bmHeight) {
-    float scale, translateX = 0, translateY = 0;
-
-    if (bmWidth * vHeight > bmHeight * vWidth) {
-      scale = vHeight / (float) bmHeight;
-      translateX = (vWidth - bmWidth * scale) * 0.5f;
-    } else {
-      scale = vWidth / (float) bmWidth;
-      translateY = (vHeight - bmHeight * scale) * 0.5f;
-    }
-
-    Matrix mMatrix = new Matrix();
-    if (scaleType == ImageView.ScaleType.FIT_XY) {
-      mMatrix.setScale(vWidth / (float) bmWidth, vHeight / (float) bmHeight);
-    } else if (scaleType == ImageView.ScaleType.FIT_CENTER) {
-      RectF src = new RectF(0, 0, bmWidth, bmHeight);
-      RectF dist = new RectF(0, 0, vWidth, vHeight);
-      mMatrix.setRectToRect(src, dist, Matrix.ScaleToFit.CENTER);
-    } else if (scaleType == ImageView.ScaleType.CENTER_CROP) {
-      mMatrix.setScale(scale, scale);
-      mMatrix.postTranslate(translateX + 0.5f, translateY + 0.5f);
-    }
-    return mMatrix;
-  }
-
-  private float[] radii;
-  private int bitmapHeight;
-  private int bitmapWidth;
-
-  private ImageDrawable() {
-
-  }
-
-  @Override
-  public void setCornerRadii(float[] radii) {
-    this.radii = radii;
-    super.setCornerRadii(radii);
-  }
-
-  @Override
-  protected void onDraw(Shape shape, Canvas canvas, Paint paint) {
-    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
-      // fix api 21 PaintDrawable crash
-      paint.setAntiAlias(false);
-    }
-    super.onDraw(shape, canvas, paint);
-  }
-
-  public
-  @Nullable
-  float[] getCornerRadii() {
-    return this.radii;
-  }
-
-  public int getBitmapHeight() {
-    return bitmapHeight;
-  }
-
-  public int getBitmapWidth() {
-    return bitmapWidth;
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/ImgURIUtil.java b/android/sdk/src/main/java/com/taobao/weex/utils/ImgURIUtil.java
deleted file mode 100644
index db8a538..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/ImgURIUtil.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.support.v4.content.res.ResourcesCompat;
-
-import java.util.List;
-
-public class ImgURIUtil {
-
-  public static Drawable getDrawableFromLoaclSrc(Context context, Uri rewrited) {
-    Resources resources = context.getResources();
-    List<String> segments = rewrited.getPathSegments();
-    if (segments.size() != 1) {
-      WXLogUtils.e("Local src format is invalid.");
-      return null;
-    }
-    int id = resources.getIdentifier(segments.get(0), "drawable", context.getPackageName());
-    return id == 0 ? null : ResourcesCompat.getDrawable(resources, id, null);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/LogLevel.java b/android/sdk/src/main/java/com/taobao/weex/utils/LogLevel.java
deleted file mode 100644
index a590820..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/LogLevel.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.util.Log;
-
-/**
- * Created by lixinke on 16/5/11.
- */
-public enum LogLevel {
-  OFF("off",8, Log.ASSERT),
-  WTF("wtf", 7, Log.ASSERT),
-  TLOG("tlog",6,Log.ERROR), //Add For Son Process
-  ERROR("error", 5, Log.ERROR),
-  WARN("warn", 4, Log.WARN),
-  INFO("info", 3, Log.INFO),
-  DEBUG("debug", 2, Log.DEBUG),
-  VERBOSE("verbose", 1, Log.VERBOSE),
-  ALL("all", 0, Log.VERBOSE),;
-  String name;
-  int value;
-  int priority;
-
-  LogLevel(String name, int value,int priority) {
-    this.name = name;
-    this.value = value;
-    this.priority = priority;
-  }
-  public String getName(){
-    return name;
-  }
-  public int getValue(){
-    return value;
-  }
-  public int getPriority(){
-    return priority;
-  }
-  public int compare(LogLevel level){
-    return value-level.value;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/OsVersion.java b/android/sdk/src/main/java/com/taobao/weex/utils/OsVersion.java
deleted file mode 100644
index 7c53095..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/OsVersion.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-/**
- * Android OS version utilities.
- */
-public class OsVersion {
-  private static boolean sIsAtLeastJB_MR2;
-
-
-  static {
-    final int v = getApiVersion();
-    sIsAtLeastJB_MR2 = v >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
-  }
-
-  /**
-   * @return True if the version of Android that we're running on is at
-   * least Jelly Bean MR2(API level 18).
-   */
-  public static boolean isAtLeastJB_MR2() {
-    return sIsAtLeastJB_MR2;
-  }
-
-  /**
-   * @return The Android API version of the running OS.
-   */
-  public static int getApiVersion() {
-    return android.os.Build.VERSION.SDK_INT;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/SingleFunctionParser.java b/android/sdk/src/main/java/com/taobao/weex/utils/SingleFunctionParser.java
deleted file mode 100644
index c67b323..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/SingleFunctionParser.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.support.annotation.NonNull;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public class SingleFunctionParser<V> extends FunctionParser<String, List<V>> {
-
-  public interface FlatMapper<V> {
-
-    V map(String raw);
-  }
-
-  public interface NonUniformMapper<V>{
-    List<V> map(List<String> raw);
-  }
-
-  /**
-   * Construct a function parser for uniform parameters.
-   * @param source the raw string representation of a group of function(s)
-   * @param mapper the mapping rule between string and corresponding type of object.
-   */
-  public SingleFunctionParser(@NonNull String source, @NonNull final FlatMapper<V> mapper) {
-    super(source, new Mapper<String, List<V>>() {
-      @Override
-      public Map<String, List<V>> map(String functionName, List<String> raw) {
-        Map<String, List<V>> map = new HashMap<String, List<V>>();
-        List<V> list = new LinkedList<V>();
-        for (String item : raw) {
-          list.add(mapper.map(item));
-        }
-        map.put(functionName, list);
-        return map;
-      }
-    });
-  }
-
-  /**
-   * Construct a function parser for non-uniform parameters.
-   * @param source the raw string representation of a group of function(s)
-   * @param mapper the mapping rule between string and corresponding type of object.
-   */
-  public SingleFunctionParser(@NonNull String source, @NonNull final NonUniformMapper<V> mapper) {
-    super(source, new Mapper<String, List<V>>() {
-      @Override
-      public Map<String, List<V>> map(String functionName, List<String> raw) {
-        Map<String, List<V>> map = new HashMap<String, List<V>>();
-        map.put(functionName, mapper.map(raw));
-        return map;
-      }
-    });
-  }
-
-  public List<V> parse(String functionName) {
-    Map<String, List<V>> map = parse();
-    if(map.containsKey(functionName)){
-      return map.get(functionName);
-    }
-    return null;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/StaticLayoutProxy.java b/android/sdk/src/main/java/com/taobao/weex/utils/StaticLayoutProxy.java
deleted file mode 100644
index ac1d660..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/StaticLayoutProxy.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.text.Layout;
-import android.text.StaticLayout;
-import android.text.TextDirectionHeuristic;
-import android.text.TextDirectionHeuristics;
-import android.text.TextPaint;
-
-import java.lang.reflect.Constructor;
-
-/**
- * Created by moxun on 2017/9/26.
- */
-
-public class StaticLayoutProxy {
-  private static Constructor<StaticLayout> layoutConstructor;
-  public static StaticLayout create(CharSequence source, TextPaint paint,
-                                    int width,
-                                    Layout.Alignment align, float spacingmult, float spacingadd,
-                                    boolean includepad, boolean forceRtl) {
-    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2 && forceRtl) {
-      TextDirectionHeuristic textDir = TextDirectionHeuristics.RTL;
-      StaticLayout rtlLayout =  createInternal(source, paint, width, align, textDir, spacingmult, spacingadd, includepad);
-      if (rtlLayout != null) {
-        return rtlLayout;
-      } else {
-        return new StaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad);
-      }
-    }
-    return new StaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad);
-  }
-
-  private static StaticLayout createInternal(CharSequence source, TextPaint paint,
-                                             int width, Layout.Alignment align, TextDirectionHeuristic textDir,
-                                             float spacingmult, float spacingadd,
-                                             boolean includepad) {
-    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
-      return null;
-    } else {
-      try {
-        if (layoutConstructor == null) {
-          Class<StaticLayout> clazz = StaticLayout.class;
-          Constructor<StaticLayout> constructor = clazz.getConstructor(CharSequence.class, TextPaint.class,
-                  int.class, Layout.Alignment.class, TextDirectionHeuristic.class,
-                  float.class, float.class,
-                  boolean.class);
-          layoutConstructor = constructor;
-        }
-        if (layoutConstructor != null) {
-          return layoutConstructor.newInstance(source, paint, width,
-                  align, textDir, spacingmult, spacingadd, includepad);
-        }
-
-      } catch (Throwable e) {
-        e.printStackTrace();
-      }
-    }
-    return null;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/Trace.java b/android/sdk/src/main/java/com/taobao/weex/utils/Trace.java
deleted file mode 100644
index cfe307e..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/Trace.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.annotation.TargetApi;
-import android.os.Build;
-
-/**
- * Hepler class for systrace.
- *
- * Note that this will run only on JBMR2 or later.
- *
- * Trace will be enabled in debug production and be disabled in release
- * production, see build.gradle.
- * If you want to enable it in release, just set sEnabled to true.
- */
-public class Trace {
-  private static final String TAG = "Weex_Trace";
-  private abstract static class AbstractTrace {
-    abstract void beginSection(String sectionName);
-    abstract void endSection();
-  }
-
-  private static final AbstractTrace sTrace;
-  private static final boolean sEnabled;
-
-  // Pick the correct trace class to handle tracing.
-  static {
-    // If you want to enable it in release, just set sEnabled to true.
-    // If you turn sEnabled on, weex would trace logs on Java side
-    // as well as on V8 side, please take care of turning sEnabled on
-    // to avoid performance impact.
-    // FIXME: weex sdk may use another build files to build and cause
-    // compiling errors if these build files don't contain any
-    // ENABLE_TRACE, just comment out the line below.
-    //sEnabled = com.taobao.weappplus_sdk.BuildConfig.ENABLE_TRACE;
-    sEnabled = false;
-
-    if (sEnabled == true && OsVersion.isAtLeastJB_MR2()) {
-      sTrace = new TraceJBMR2();
-    } else {
-      sTrace = new TraceDummy();
-    }
-  }
-
-  public static final boolean getTraceEnabled() {
-    return sEnabled;
-  }
-
-  /**
-   * Writes a trace message to indicate that a given section of code has begun.
-   * This call must be followed by a corresponding call to {@link #endSection()}
-   * on the same thread.
-   *
-   * <p class="note"> If sectionName contains '|', '\n' and '\0', these characters
-   * will be repaced with a space character.
-   *
-   * @param sectionName The name of code section to appear in the trace.
-   */
-  public static void beginSection(String sectionName) {
-    android.util.Log.i(TAG, "beginSection() " + sectionName);
-    sTrace.beginSection(sectionName);
-  }
-
-  /**
-   * Writes a trace message to indicate that a given section of code has ended.
-   * This call must be preceeded by a corresponding call to {@link #beginSection(String)}
-   * on the same thread.
-   */
-  public static void endSection() {
-    sTrace.endSection();
-    android.util.Log.i(TAG, "endSection()");
-  }
-
-  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
-  private static final class TraceJBMR2 extends AbstractTrace {
-    @Override
-    void beginSection(String sectionName) {
-      android.os.Trace.beginSection(sectionName);
-    }
-
-    @Override
-    void endSection() {
-      android.os.Trace.endSection();
-    }
-  }
-
-  private static final class TraceDummy extends AbstractTrace {
-    @Override
-    void beginSection(String sectionName) {
-    }
-
-    @Override
-    void endSection() {
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/TypefaceUtil.java b/android/sdk/src/main/java/com/taobao/weex/utils/TypefaceUtil.java
deleted file mode 100644
index a6ad566..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/TypefaceUtil.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.content.Intent;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.net.Uri;
-import android.support.v4.content.LocalBroadcastManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.common.WXResponse;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.font.FontAdapter;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by sospartan on 7/13/16.
- */
-public class TypefaceUtil {
-  public static final String FONT_CACHE_DIR_NAME = "font-family";
-  private final static String TAG = "TypefaceUtil";
-  private final static Map<String, FontDO> sCacheMap = new HashMap<>(); //Key: fontFamilyName
-
-  public static final String ACTION_TYPE_FACE_AVAILABLE = "type_face_available";
-
-  public static void putFontDO(FontDO fontDO) {
-    if (fontDO != null && !TextUtils.isEmpty(fontDO.getFontFamilyName())) {
-      sCacheMap.put(fontDO.getFontFamilyName(), fontDO);
-    }
-  }
-
-  public static void registerNativeFont(Map<String, Typeface> fonts) {
-    if (fonts != null && fonts.size() > 0) {
-      for (Map.Entry<String, Typeface> font : fonts.entrySet()) {
-        FontDO fontDO = new FontDO(font.getKey(), font.getValue());
-        putFontDO(fontDO);
-        if (WXEnvironment.isApkDebugable()){
-          WXLogUtils.d("TypefaceUtil", "register new typeface: " + font.getKey());
-        }
-      }
-    }
-  }
-
-  public static FontDO getFontDO(String fontFamilyName) {
-    return sCacheMap.get(fontFamilyName);
-  }
-
-  public static void removeFontDO(String fontFamilyName) {
-    sCacheMap.remove(fontFamilyName);
-  }
-
-  public static void applyFontStyle(Paint paint, int style, int weight, String family) {
-    int oldStyle;
-    Typeface typeface = paint.getTypeface();
-    if (typeface == null) {
-      oldStyle = 0;
-    } else {
-      oldStyle = typeface.getStyle();
-    }
-
-    int want = 0;
-    if ((weight == Typeface.BOLD)
-            || ((oldStyle & Typeface.BOLD) != 0 && weight == WXStyle.UNSET)) {
-      want |= Typeface.BOLD;
-    }
-
-    if ((style == Typeface.ITALIC)
-            || ((oldStyle & Typeface.ITALIC) != 0 && style == WXStyle.UNSET)) {
-      want |= Typeface.ITALIC;
-    }
-
-    if (family != null) {
-      typeface = getOrCreateTypeface(family, want);
-    }
-
-    if (typeface != null) {
-      paint.setTypeface(Typeface.create(typeface, want));
-    } else {
-      paint.setTypeface(Typeface.defaultFromStyle(want));
-    }
-  }
-
-  public static Typeface getOrCreateTypeface(String family, int style) {
-    FontDO fontDo = sCacheMap.get(family);
-    if (fontDo != null && fontDo.getTypeface() != null) {
-      return fontDo.getTypeface();
-    }
-
-    return Typeface.create(family, style);
-  }
-
-  private static void loadFromAsset(FontDO fontDo,String path){
-    try {
-      Typeface typeface = Typeface.createFromAsset(WXEnvironment.getApplication().getAssets(), path);
-      if (typeface != null) {
-        if(WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d(TAG, "load asset file success");
-        }
-        fontDo.setState(FontDO.STATE_SUCCESS);
-        fontDo.setTypeface(typeface);
-      } else {
-        WXLogUtils.e(TAG, "Font asset file not found " + fontDo.getUrl());
-      }
-    } catch (Exception e) {
-      WXLogUtils.e(TAG, e.toString());
-    }
-  }
-
-  public static void loadTypeface(final FontDO fontDo, boolean notify) {
-    if (fontDo != null && fontDo.getTypeface() == null &&
-            (fontDo.getState() == FontDO.STATE_FAILED || fontDo.getState() == FontDO.STATE_INIT)) {
-      fontDo.setState(FontDO.STATE_LOADING);
-      if (fontDo.getType() == FontDO.TYPE_LOCAL) {
-        Uri uri = Uri.parse(fontDo.getUrl());
-        loadFromAsset(fontDo,uri.getPath().substring(1));//exclude slash
-      } else if (fontDo.getType() == FontDO.TYPE_NETWORK) {
-        final String url = fontDo.getUrl();
-        final String fontFamily = fontDo.getFontFamilyName();
-        final String fileName = WXFileUtils.md5(url);
-        //url.replace('/', '_').replace(':', '_');
-        File dir = new File(getFontCacheDir());
-        if(!dir.exists()){
-          dir.mkdirs();
-        }
-        final String fullPath =  dir.getAbsolutePath()+ File.separator +fileName;
-        if (!loadLocalFontFile(fullPath, fontFamily, false)) {
-          downloadFontByNetwork(url, fullPath, fontFamily);
-        }
-      } else if (fontDo.getType() == FontDO.TYPE_FILE || fontDo.getType() == FontDO.TYPE_BASE64) {
-        boolean result = loadLocalFontFile(fontDo.getUrl(), fontDo.getFontFamilyName(), false);
-        if (!result) {
-          fontDo.setState(FontDO.STATE_FAILED);
-        }
-      }
-      return;
-    }
-    if(notify){
-         notifyFontAvailable(false, fontDo);
-    }
-  }
-
-  private static void downloadFontByNetwork(final String url, final String fullPath, final String fontFamily) {
-    IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter();
-    if (adapter == null) {
-      WXLogUtils.e(TAG, "downloadFontByNetwork() IWXHttpAdapter == null");
-      return;
-    }
-    WXRequest request = new WXRequest();
-    request.url = url;
-    request.method = "GET";
-    adapter.sendRequest(request, new IWXHttpAdapter.OnHttpListener() {
-      @Override
-      public void onHttpStart() {
-        if(WXEnvironment.isApkDebugable()) {
-          WXLogUtils.d(TAG, "downloadFontByNetwork begin url:" + url);
-        }
-      }
-
-      @Override
-      public void onHeadersReceived(int statusCode, Map<String, List<String>> headers) {
-
-      }
-
-      @Override
-      public void onHttpUploadProgress(int uploadProgress) {
-
-      }
-
-      @Override
-      public void onHttpResponseProgress(int loadedLength) {
-
-      }
-
-      @Override
-      public void onHttpFinish(WXResponse response) {
-        int statusCode = 0;
-        if (!TextUtils.isEmpty(response.statusCode)) {
-          try {
-            statusCode = Integer.parseInt(response.statusCode);
-          } catch (NumberFormatException e) {
-            statusCode = 0;
-            WXLogUtils.e(TAG, "IWXHttpAdapter onHttpFinish statusCode:" + response.statusCode);
-          }
-        }
-        boolean result;
-        if (statusCode >= 200 && statusCode <= 299 && response.originalData != null) {
-          result = WXFileUtils.saveFile(fullPath, response.originalData, WXEnvironment.getApplication());
-          if (result) {
-            result = loadLocalFontFile(fullPath, fontFamily, true);
-          } else {
-            if(WXEnvironment.isApkDebugable()) {
-              WXLogUtils.d(TAG, "downloadFontByNetwork() onHttpFinish success, but save file failed.");
-            }
-          }
-        } else {
-          result = false;
-        }
-
-        if (!result) {
-          FontDO fontDO = sCacheMap.get(fontFamily);
-          if (fontDO != null) {
-            fontDO.setState(FontDO.STATE_FAILED);
-          }
-        }
-      }
-    });
-  }
-
-  private static boolean loadLocalFontFile(final String path, final String fontFamily, boolean hasNetworkDowload) {
-    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(fontFamily)) {
-      return false;
-    }
-    try {
-      File file = new File(path);
-      if (!file.exists()) {
-        return false;
-      }
-      Typeface typeface = Typeface.createFromFile(path);
-      if (typeface != null) {
-        final FontDO fontDo = sCacheMap.get(fontFamily);
-        if (fontDo != null) {
-          fontDo.setState(FontDO.STATE_SUCCESS);
-          fontDo.setTypeface(typeface);
-          fontDo.setFilePath(path);
-          if(WXEnvironment.isApkDebugable()) {
-            WXLogUtils.d(TAG, "load local font file success");
-          }
-
-          if(hasNetworkDowload) {
-            /**
-             * wxtext may be measured when font not load, when register broadcast receiver,
-             * this broadcast has been send, which cause textview not rendered right.
-             * delay broadcast ensure text will render right
-             * */
-            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
-              @Override
-              public void run() {
-               notifyFontAvailable(true, fontDo);
-              }
-            }, 100);
-          }else{
-             notifyFontAvailable(true, fontDo);
-          }
-          return true;
-        }
-      } else {
-        WXLogUtils.e(TAG, "load local font file failed, can't create font.");
-      }
-    } catch (Exception e) {
-      WXLogUtils.e(TAG, e.toString());
-    }
-    return false;
-  }
-
-  private static void notifyFontAvailable(boolean sendBroadcast, FontDO fontDO){
-    if(sendBroadcast){
-      Intent intent = new Intent(ACTION_TYPE_FACE_AVAILABLE);
-      intent.putExtra("fontFamily", fontDO.getFontFamilyName());
-      intent.putExtra("filePath", fontDO.getFilePath());
-      intent.putExtra("fontUrl", fontDO.getUrl());
-      LocalBroadcastManager.getInstance(WXEnvironment.getApplication()).sendBroadcast(intent);
-    }
-    FontAdapter fontAdapter = WXSDKManager.getInstance().getFontAdapter();
-    if(fontAdapter != null){
-        fontAdapter.onFontLoad(fontDO.getFontFamilyName(), fontDO.getUrl(), fontDO.getFilePath());
-    }
-  }
-
-  private static String getFontCacheDir() {
-    return WXEnvironment.getApplication().getCacheDir() + "/" + FONT_CACHE_DIR_NAME;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXDataStructureUtil.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXDataStructureUtil.java
deleted file mode 100644
index ee28e45..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXDataStructureUtil.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import java.util.HashMap;
-
-public class WXDataStructureUtil {
-
-  /**
-   * The largest power of two that can be represented as an {@code int}.
-   */
-  private static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
-
-  /**
-   * Creates a {@code HashMap} instance, with a high enough "initial capacity" that it <i>should</i>
-   * hold {@code expectedSize} elements without growth. This behavior cannot be broadly guaranteed,
-   * but it is observed to be true for OpenJDK 1.7. It also can't be guaranteed that the method
-   * isn't inadvertently <i>oversizing</i> the returned map.
-   *
-   * @param expectedSize the number of entries you expect to add to the returned map
-   * @return a new, empty {@code HashMap} with enough capacity to hold {@code expectedSize} entries
-   * without resizing
-   * @throws IllegalArgumentException if {@code expectedSize} is negative
-   */
-  public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {
-    return new HashMap<>(capacity(expectedSize));
-  }
-
-  /**
-   * Returns a capacity that is sufficient to keep the map from being resized as long as it grows no
-   * larger than expectedSize and the load factor is >= its default (0.75).
-   */
-  private static int capacity(int expectedSize) {
-    if (expectedSize < 3) {
-      checkNonnegative(expectedSize, "expectedSize");
-      return expectedSize + 1;
-    }
-    if (expectedSize < MAX_POWER_OF_TWO) {
-      // This is the calculation used in JDK8 to resize when a putAll
-      // happens; it seems to be the most conservative calculation we
-      // can make.  0.75 is the default load factor.
-      return (int) ((float) expectedSize / 0.75F + 1.0F);
-    }
-    return Integer.MAX_VALUE; // any large value
-  }
-
-  private static int checkNonnegative(int value, String name) {
-    if (value < 0) {
-      throw new IllegalArgumentException(name + " cannot be negative but was: " + value);
-    }
-    return value;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXDeviceUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXDeviceUtils.java
deleted file mode 100644
index c5dd78b..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXDeviceUtils.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.content.Context;
-import android.os.Build;
-
-public class WXDeviceUtils {
-
-
-    public static boolean isAutoResize(Context context){
-        if(context == null){
-            return false;
-        }
-        return isMateX(context) || isGalaxyFold(context);
-    }
-
-    /**
-     * Mate X
-     * */
-    public static boolean isMateX(Context context) {
-        return "HUAWEI".equalsIgnoreCase(Build.BRAND) && ("unknownRLI".equalsIgnoreCase(Build.DEVICE) || ("HWTAH".equalsIgnoreCase(Build.DEVICE)));
-    }
-
-
-    /**
-     * Galaxy Fopld
-     * */
-    public static boolean isGalaxyFold(Context context) {
-
-        if("samsung".equalsIgnoreCase(Build.BRAND) && "SM-F9000".equalsIgnoreCase(Build.MODEL)) {
-            return true;
-        }
-
-        return false;
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXDomUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXDomUtils.java
deleted file mode 100644
index bfd0ea5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXDomUtils.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.support.annotation.NonNull;
-import com.taobao.weex.dom.CSSConstants;
-import com.taobao.weex.dom.CSSShorthand.EDGE;
-import com.taobao.weex.dom.WXStyle;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.dom.CSSShorthand;
-
-public class WXDomUtils {
-
-  /**
-   * Get the content width of the dom.
-   * @return the width of the dom that excludes left-padding, left-border-width,
-   * right-border-width and right-padding.
-   */
-  public static float getContentWidth(WXComponent component) {
-    float rawWidth = component.getLayoutWidth();
-    float leftPadding, rightPadding, leftBorder, rightBorder;
-    CSSShorthand padding = component.getPadding();
-    CSSShorthand border = component.getBorder();
-
-    if (!CSSConstants.isUndefined((leftPadding = padding.get(CSSShorthand.EDGE.LEFT)))) {
-      rawWidth -= leftPadding;
-    }
-    if (!CSSConstants.isUndefined((rightPadding = padding.get(CSSShorthand.EDGE.RIGHT)))) {
-      rawWidth -= rightPadding;
-    }
-
-    if (!CSSConstants.isUndefined(leftBorder = border.get(CSSShorthand.EDGE.LEFT))) {
-      rawWidth -= leftBorder;
-    }
-    if (!CSSConstants.isUndefined(rightBorder = border.get(CSSShorthand.EDGE.RIGHT))) {
-      rawWidth -= rightBorder;
-    }
-    return rawWidth;
-  }
-
-  /**
-   * Get the content height of the dom.
-   * @return the height of the dom that excludes top-padding, top-border-width, bottom-padding
-   * and bottom-border-width.
-   */
-  public static float getContentHeight(WXComponent component) {
-    float rawHeight = component.getLayoutHeight();
-    float topPadding, bottomPadding, topBorder, bottomBorder;
-    CSSShorthand padding = component.getPadding();
-    CSSShorthand border = component.getBorder();
-
-    if (!CSSConstants.isUndefined((topPadding = padding.get(CSSShorthand.EDGE.TOP)))) {
-      rawHeight -= topPadding;
-    }
-    if (!CSSConstants.isUndefined((bottomPadding = padding.get(CSSShorthand.EDGE.BOTTOM)))) {
-      rawHeight -= bottomPadding;
-    }
-
-    if (!CSSConstants.isUndefined(topBorder = border.get(CSSShorthand.EDGE.TOP))) {
-      rawHeight -= topBorder;
-    }
-    if (!CSSConstants.isUndefined(bottomBorder = border.get(CSSShorthand.EDGE.BOTTOM))) {
-      rawHeight -= bottomBorder;
-    }
-    return rawHeight;
-  }
-
-  public static float getContentWidth(
-      @NonNull CSSShorthand padding,
-      @NonNull CSSShorthand border,
-      float layoutWidth){
-    float leftPadding, rightPadding, leftBorder, rightBorder;
-
-    if (!CSSConstants.isUndefined((leftPadding = padding.get(EDGE.LEFT)))) {
-      layoutWidth -= leftPadding;
-    }
-    if (!CSSConstants.isUndefined((rightPadding = padding.get(EDGE.RIGHT)))) {
-      layoutWidth -= rightPadding;
-    }
-
-    if (!CSSConstants.isUndefined(leftBorder = border.get(EDGE.LEFT))) {
-      layoutWidth -= leftBorder;
-    }
-    if (!CSSConstants.isUndefined(rightBorder = border.get(EDGE.RIGHT))) {
-      layoutWidth -= rightBorder;
-    }
-    return layoutWidth;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXExceptionUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXExceptionUtils.java
deleted file mode 100644
index 1bf7d7f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXExceptionUtils.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.adapter.IWXJSExceptionAdapter;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXErrorCode.ErrorGroup;
-import com.taobao.weex.common.WXJSExceptionInfo;
-import com.taobao.weex.common.WXPerformance;
-import com.taobao.weex.performance.WXAnalyzerDataTransfer;
-import com.taobao.weex.performance.WXInstanceApm;
-import com.taobao.weex.performance.WXStateRecord;
-
-/**
- * Created on 2017/10/13.
- */
-
-public class WXExceptionUtils {
-
-    private static Set<String> sGlobalExceptionRecord = new CopyOnWriteArraySet<String>();
-
-	/**
-	 * degradeUrl for degrade case
-	 */
-	public static String degradeUrl = "BundleUrlDefaultDegradeUrl";
-
-	private static boolean checkNeedReportCauseRepeat(String instanceId,WXErrorCode errCode,String exception){
-
-	    if (TextUtils.isEmpty(exception)){
-	        return true;
-        }
-
-        if (null != errCode && errCode.getErrorGroup() != ErrorGroup.JS){
-	        return true;
-        }
-
-        if (TextUtils.isEmpty(instanceId)){
-            instanceId = "instanceIdNull";
-        }
-
-        String targetException = exception.length() > 200 ?exception.substring(0,200) : exception;
-        Set<String> recordExceptionHistory= null;
-
-        WXSDKInstance instance =  WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-        if (null == instance){
-            recordExceptionHistory = sGlobalExceptionRecord;
-        }else {
-            recordExceptionHistory =  instance.getApmForInstance().exceptionRecord;
-        }
-
-        if (null == recordExceptionHistory){
-            return true;
-        }
-
-        if (recordExceptionHistory.contains(targetException)){
-            return false;
-        }
-        recordExceptionHistory.add(targetException);
-        return true;
-    }
-
-
-
-
-	/**
-	 * commitCriticalExceptionRT eg:JsRuntime Exception or JsFramework Init Exception
-	 * @param instanceId
-	 * @param errCode
-	 * @param function
-	 * @param exception
-	 * @param extParams
-	 */
-	public static void commitCriticalExceptionRT(@Nullable final String instanceId,
-												 @Nullable final WXErrorCode errCode,
-												 @Nullable final String function,
-												 @Nullable final String exception,
-												 @Nullable final Map<String,String> extParams ) {
-
-        try {
-            WXLogUtils.e("weex","commitCriticalExceptionRT :"+errCode+"exception"+exception);
-            WXStateRecord.getInstance().recordException(instanceId,exception);
-            IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
-            boolean doCheck = true;
-            if (null != configAdapter){
-                String value = configAdapter.getConfig("wxapm","check_repeat_report","true");
-                doCheck = "true".equalsIgnoreCase(value);
-            }
-            boolean doReport =true;
-            if (doCheck){
-                doReport = checkNeedReportCauseRepeat(instanceId,errCode,exception);
-            }
-            if (!doReport){
-                return;
-            }
-        }catch (Throwable e){
-            e.printStackTrace();
-        }
-
-
-		commitCriticalExceptionWithDefaultUrl(
-		    "BundleUrlDefault",
-            instanceId,
-            errCode,
-            function,
-            exception,
-            extParams
-        );
-	}
-
-    public static void commitCriticalExceptionWithDefaultUrl(
-        @Nullable final String defaultUrl,
-        @Nullable final String instanceId,
-        @Nullable final WXErrorCode errCode,
-        @Nullable final String function,
-        @Nullable final String exception,
-        @Nullable final Map<String,String> extParams
-    ){
-        IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
-        WXSDKInstance instance = null;
-        WXJSExceptionInfo exceptionCommit;
-        String bundleUrlCommit = TextUtils.isEmpty(defaultUrl)?"BundleUrlDefault":defaultUrl;
-        String instanceIdCommit = "InstanceIdDefalut";
-        String exceptionMsgCommit = exception;
-        Map<String, String> commitMap = extParams;
-        if (null == commitMap){
-            commitMap = new HashMap<>();
-        }
-        commitMap.put("wxSdkInitStartTime", String.valueOf(WXEnvironment.sSDKInitStart));
-        commitMap.put("wxSDKInitCostTime", String.valueOf(WXEnvironment.sSDKInitTime));
-        commitMap.put("wxSDKCurExceptionTime", String.valueOf(System.currentTimeMillis()));
-        commitMap.put("wxUseRuntimeApi",String.valueOf(WXEnvironment.sUseRunTimeApi));
-        if (!TextUtils.isEmpty(instanceId)) {
-            instanceIdCommit = instanceId;
-            instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
-
-            if (null != instance) {
-                bundleUrlCommit = instance.getApmForInstance().reportPageName;
-                Object loadLength = instance.getApmForInstance().extInfo.get(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH);
-                String loadLengthStr = (loadLength instanceof Integer)?String.valueOf(loadLength):"unknownLength";
-                commitMap.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadLengthStr);
-                commitMap.put("templateInfo",instance.getTemplateInfo());
-                if (TextUtils.isEmpty(bundleUrlCommit) || bundleUrlCommit.equals(WXPerformance.DEFAULT)) {
-                    if (!TextUtils.equals(degradeUrl, "BundleUrlDefaultDegradeUrl")) {
-                        bundleUrlCommit = degradeUrl;
-                    } else
-                        bundleUrlCommit = WXSDKInstance.requestUrl;
-                }
-                for (Map.Entry<String,String> entry: instance.getContainerInfo().entrySet()){
-                    commitMap.put(entry.getKey(),entry.getValue());
-                }
-                commitMap.put("wxStageList",convertStageToStr(instance));
-                String bundleTemplate = instance.getTemplate();
-                if (null == bundleTemplate){
-                    bundleTemplate = "has recycle by gc";
-                }else {
-                    int length = bundleTemplate.length();
-                    bundleTemplate = bundleTemplate.substring(0,Math.min(length,300));
-                }
-                commitMap.put("wxTemplateOfBundle",bundleTemplate);
-
-                Long pageStartTime = instance.getApmForInstance().stageMap.get(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
-                if (null == pageStartTime){
-                    pageStartTime = instance.getApmForInstance().stageMap.get(WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN);
-                }
-                if (null != pageStartTime){
-                    commitMap.put("wxUseTime", String.valueOf(WXUtils.getFixUnixTime() - pageStartTime));
-                }
-            }
-        } else {//instance is null for instance id is null
-            if (commitMap.size() > 0) {
-                bundleUrlCommit = TextUtils.isEmpty(commitMap.get("weexUrl")) ? commitMap.get("weexUrl")
-                    : commitMap.get("bundleUrl");
-            }
-        }
-
-        String illegalValue = commitMap.get("errorCode");
-        if (null != illegalValue && illegalValue.length()>200){
-            commitMap.remove("errorCode");
-        }
-
-        exceptionCommit = new WXJSExceptionInfo(instanceIdCommit, bundleUrlCommit, errCode, function, exceptionMsgCommit, commitMap);
-        if (adapter != null) {
-            adapter.onJSException(exceptionCommit);
-        }
-
-        WXAnalyzerDataTransfer.transferError(exceptionCommit, instanceId);
-    }
-
-    private static String convertStageToStr(WXSDKInstance instance) {
-        if (null == instance || null == instance.getApmForInstance() || instance.getApmForInstance().stageMap.isEmpty()) {
-            return "noStageRecord";
-        }
-        List<Entry<String, Long>> list = new ArrayList<>(instance.getApmForInstance().stageMap.entrySet());
-        Collections.sort(list, new Comparator<Entry<String, Long>>() {
-            @Override
-            public int compare(Entry<String, Long> o1, Entry<String, Long> o2) {
-                return (int)(o1.getValue() - o2.getValue());
-            }
-        });
-
-        StringBuilder builder = new StringBuilder();
-        for (Map.Entry<String, Long> entry : list) {
-            builder.append(entry.getKey()).append(':').append(entry.getValue()).append("->");
-        }
-        return builder.toString();
-    }
-
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXFileUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXFileUtils.java
deleted file mode 100644
index 15121a5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXFileUtils.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Base64;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-
-public class WXFileUtils {
-
-  /**
-   * Load file in device directory, if not exist, load from asset directory.
-   * @param path FilePath
-   * @param context Weex Context
-   * @return the Content of the file
-   */
-  public static String loadFileOrAsset(String path, Context context) {
-    if (!TextUtils.isEmpty(path)) {
-      File file = new File(path);
-      if (file.exists()) {
-        try {
-          FileInputStream fis = new FileInputStream(file);
-          return readStreamToString(fis);
-        } catch (FileNotFoundException e) {
-          e.printStackTrace();
-        }
-      } else {
-        return loadAsset(path, context);
-      }
-    }
-    return "";
-  }
-
-  /**
-   * Load file in asset directory.
-   * @param path FilePath
-   * @param context Weex Context
-   * @return the Content of the file
-   */
-  public static String loadAsset(String path, Context context) {
-    if (context == null || TextUtils.isEmpty(path)) {
-      return null;
-    }
-    InputStream inputStream = null;
-    try {
-      inputStream = context.getAssets().open(path);
-      return readStreamToString(inputStream);
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-    return "";
-  }
-
-  public static String readStreamToString(InputStream inputStream) {
-    BufferedReader bufferedReader = null;
-    try {
-      StringBuilder builder = new StringBuilder(inputStream.available() + 10);
-      bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
-      char[] data = new char[4096];
-      int len = -1;
-      while ((len = bufferedReader.read(data)) > 0) {
-        builder.append(data, 0, len);
-      }
-
-      return builder.toString();
-    } catch (IOException e) {
-      e.printStackTrace();
-      WXLogUtils.e("", e);
-    } finally {
-      try {
-        if (bufferedReader != null)
-          bufferedReader.close();
-      } catch (IOException e) {
-        WXLogUtils.e("WXFileUtils loadAsset: ", e);
-      }
-      try {
-        if (inputStream != null)
-          inputStream.close();
-      } catch (IOException e) {
-        WXLogUtils.e("WXFileUtils loadAsset: ", e);
-      }
-    }
-
-    return "";
-  }
-
-  public static byte[] readBytesFromAssets(String path, Context context) {
-    if (context == null || TextUtils.isEmpty(path)) {
-      return null;
-    }
-    InputStream inputStream = null;
-    try {
-      inputStream = context.getAssets().open(path);
-      byte[] data = new byte[4096];
-      int length = inputStream.read(data);
-      byte[] result = new byte[length];
-      System.arraycopy(data, 0, result, 0, length);
-      return result;
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-    return null;
-  }
-
-  public static boolean saveFile(String path, byte[] content, Context context) {
-    if (TextUtils.isEmpty(path) || content == null || context == null) {
-      return false;
-    }
-    FileOutputStream outStream = null;
-    try {
-      outStream = new FileOutputStream(path);
-      outStream.write(content);
-      return true;
-    } catch (Exception e) {
-      WXLogUtils.e("WXFileUtils saveFile: " + WXLogUtils.getStackTrace(e));
-    } finally {
-      if (outStream != null) {
-        try {
-          outStream.close();
-        } catch (IOException e) {
-          e.printStackTrace();
-        }
-      }
-    }
-    return false;
-  }
-
-  public static String md5(String  template){
-    try {
-      if(template == null){
-        return  "";
-      }
-      return  md5(template.getBytes("UTF-8"));
-    } catch (UnsupportedEncodingException e) {
-      return  "";
-    }
-  }
-
-  public static String md5(byte[] bts){
-    try {
-      MessageDigest digest = MessageDigest.getInstance("MD5");
-      digest.update(bts);
-      BigInteger bigInt = new BigInteger(1, digest.digest());
-      return  bigInt.toString(16);
-    } catch (NoSuchAlgorithmException e) {;
-      return  "";
-    }
-  }
-
-  public static String base64Md5(String  template){
-    try {
-      if(template == null){
-        return  "";
-      }
-      return  base64Md5(template.getBytes("UTF-8"));
-    } catch (UnsupportedEncodingException e) {
-      return  "";
-    }
-  }
-
-  public static String base64Md5(byte[] bts){
-    try {
-      MessageDigest digest = MessageDigest.getInstance("MD5");
-      digest.update(bts);
-      return Base64.encodeToString(digest.digest(), Base64.NO_WRAP);
-    } catch (NoSuchAlgorithmException e) {;
-      return  "";
-    }
-  }
-
-  public static void extractSo(String apkFile, String path) throws IOException {
-    ZipFile zip = new ZipFile(apkFile);
-    InputStream zipInputStream = new BufferedInputStream(new FileInputStream(apkFile));
-    ZipInputStream zin = new ZipInputStream(zipInputStream);
-    ZipEntry zipEntry;
-    while ((zipEntry = zin.getNextEntry()) != null) {
-      if(zipEntry.isDirectory()){
-        continue;
-      }
-      if(zipEntry.getName().contains("lib/armeabi/") &&
-              (zipEntry.getName().contains("weex") || zipEntry.getName().equals("libJavaScriptCore.so"))){
-        String[] fileNames = zipEntry.getName().split("/");
-        String fileName = fileNames[fileNames.length - 1];
-        InputStream inputStream = zip.getInputStream(zipEntry);
-        byte[] data = new byte[1024];
-        File zipFile = new File(path + "/" + fileName);
-        if(zipFile.exists()) {
-          zipFile.delete();
-        }
-
-        zipFile.createNewFile();
-
-        FileOutputStream outputStream =new FileOutputStream(zipFile);
-        while (inputStream.read(data) != -1) {
-          outputStream.write(data);
-        }
-        outputStream.close();
-
-      }
-    }
-    zin.closeEntry();
-  }
-
-  public static void copyFile(File oldFile, File newFile) {
-    FileInputStream inputStream = null;
-    FileOutputStream outputStream = null;
-    try {
-      inputStream = new FileInputStream(oldFile);
-      byte[] data = new byte[1024];
-      outputStream = new FileOutputStream(newFile);
-      while (inputStream.read(data) != -1) {
-        outputStream.write(data);
-      }
-      inputStream.close();
-      outputStream.close();
-    } catch (Exception e) {
-      WXLogUtils.e("copyFile " + e.getMessage() + ": " + oldFile.getAbsolutePath() + ": " + newFile.getAbsolutePath());
-      if (inputStream != null) {
-        try {
-          inputStream.close();
-        } catch (IOException e1) {
-          e1.printStackTrace();
-        }
-      }
-
-      if (outputStream != null) {
-        try {
-          outputStream.close();
-        } catch (IOException e1) {
-          e1.printStackTrace();
-        }
-      }
-    }
-  }
-
-  public static void copyFileWithException(File oldFile,File newFile ) throws Exception{
-    FileInputStream inputStream = null;
-    FileOutputStream outputStream = null;
-    try {
-      inputStream = new FileInputStream(oldFile);
-      byte[] data = new byte[1024];
-      outputStream = new FileOutputStream(newFile);
-      while (inputStream.read(data) != -1) {
-        outputStream.write(data);
-      }
-    }catch (Exception e){
-      throw e;
-    }finally {
-      closeIo(inputStream);
-      closeIo(outputStream);
-    }
-  }
-
-  public static void closeIo(Closeable c){
-    if (null == c){
-      return;
-    }
-    try {
-      c.close();
-    }catch (Throwable e){
-      e.printStackTrace();
-    }
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXInterception.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXInterception.java
deleted file mode 100644
index c667c94..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXInterception.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-public class WXInterception {
-
-  private WXInterception() {
-  }
-
-  @SuppressWarnings("unchecked")
-  public static <T> T proxy(final Object delegatee, final Class<T> interface_class, final InterceptionHandler<T> handler) throws IllegalArgumentException {
-    if (delegatee instanceof Intercepted) {
-      return (T) delegatee;
-    }
-    handler.setDelegate((T) delegatee);
-    return (T) Proxy.newProxyInstance(WXInterception.class.getClassLoader(), new Class<?>[]{interface_class, Intercepted.class}, handler);
-  }
-
-  @SuppressWarnings("unchecked")
-  public static <T> T proxy(final Object delegatee, final InterceptionHandler<T> handler, final Class<?>... interfaces) throws IllegalArgumentException {
-    //if (Proxy.isProxyClass(delegatee.getClass())) return (T) delegatee;
-    handler.setDelegate((T) delegatee);
-    return (T) Proxy.newProxyInstance(WXInterception.class.getClassLoader(), interfaces, handler);
-  }
-
-  private interface Intercepted {
-
-  }        // A mark to identify our proxy class
-
-  /**
-   * Derive this class and override {@link #invoke(Object, Method, Object[])} to implement an
-   * interception handler.
-   */
-  public abstract static class InterceptionHandler<T> implements InvocationHandler {
-
-    private T mDelegate;
-
-    /**
-     * Derived class should override this method and call <code>super.invoke(...)</code> to delegate the
-     * procedure to original delegate instance if needed.
-     *
-     * @param proxy is ignored, instead the actual delegate instance will be used to invoke this method on.
-     */
-    @Override
-    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
-      try {
-        return method.invoke(delegate(), args);
-      } catch (IllegalArgumentException e) {/* Should never happen */
-        WXLogUtils.e("", e);
-        return null;
-      } catch (IllegalAccessException e) {/* Should never happen */
-        WXLogUtils.e("", e);
-        return null;
-      } catch (InvocationTargetException e) {
-        throw e.getTargetException();
-      }
-    }
-
-    protected T delegate() {
-      return mDelegate;
-    }
-
-    void setDelegate(final T delegate) {
-      mDelegate = delegate;
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXJsonUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXJsonUtils.java
deleted file mode 100644
index cb8e2a7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXJsonUtils.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-
-import android.support.annotation.NonNull;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.common.WXRuntimeException;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Tool for parse JSON
- */
-public class WXJsonUtils {
-
-
-  public @NonNull static <T> List<T> getList(String json, Class<T> clazz) {
-    List<T> result = null;
-    try {
-      result = JSONObject.parseArray(json, clazz);
-    } catch (Exception e) {
-      e.printStackTrace();
-      result = new ArrayList<>();
-    }
-    return result;
-  }
-
-  public @NonNull static String fromObjectToJSONString(Object obj, boolean WriteNonStringKeyAsString){
-    try {
-      if(WriteNonStringKeyAsString) {
-        return JSON.toJSONString(obj, SerializerFeature.WriteNonStringKeyAsString);
-      }else {
-        return JSON.toJSONString(obj);
-      }
-    }catch(Exception e){
-      if(WXEnvironment.isApkDebugable()){
-        throw new WXRuntimeException("fromObjectToJSONString parse error!");
-      }
-      WXLogUtils.e("fromObjectToJSONString error:", e);
-      return "{}";
-    }
-  }
-  public @NonNull static String fromObjectToJSONString(Object obj) {
-
-    return fromObjectToJSONString(obj,false);
-  }
-
-  /**
-   * Put the map info in the JSONObject to the container.
-   * This method check for null value in the JSONObject
-   * and won't put the null value in the container.
-   * As {@link ConcurrentHashMap#putAll(Map)} will throws an exception if the key or value to
-   * be put is null, it is necessary to invoke this method as replacement of
-   * {@link Map#putAll(Map)}
-   * @param container container to contain the JSONObject.
-   * @param rawValue jsonObject, contains map info.
-   */
-  public static void putAll(Map<String, Object> container, JSONObject rawValue) {
-    String key;
-    Object value;
-    for (Map.Entry<String, Object> entry : rawValue.entrySet()) {
-      key = entry.getKey();
-      value = entry.getValue();
-      if (key != null && value != null) {
-        container.put(key, value);
-      }
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
deleted file mode 100644
index d8bc7a9..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.alibaba.fastjson.JSON;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.performance.WXStateRecord;
-import com.taobao.weex.utils.tools.LogDetail;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import static com.taobao.weex.utils.tools.TimeCalculator.TIMELINE_TAG;
-
-public class WXLogUtils {
-
-  public static final String WEEX_TAG = "weex";
-  public static final String WEEX_PERF_TAG = "weex_perf";
-
-  private static final String CLAZZ_NAME_LOG_UTIL = "com.taobao.weex.devtools.common.LogUtil";
-
-  private static StringBuilder builder = new StringBuilder(50);
-  private static HashMap<String, Class> clazzMaps = new HashMap<>(2);
-  private static List<JsLogWatcher> jsLogWatcherList;
-  private static LogWatcher sLogWatcher;
-
-  static {
-    clazzMaps.put(CLAZZ_NAME_LOG_UTIL, loadClass(CLAZZ_NAME_LOG_UTIL));
-    jsLogWatcherList = new ArrayList<>();
-  }
-
-  private static Class loadClass(String clazzName) {
-    Class<?> clazz = null;
-    try {
-      clazz = Class.forName(clazzName);
-      if (clazz != null) {
-        clazzMaps.put(clazzName, clazz);
-      }
-    } catch (ClassNotFoundException e) {
-      // ignore
-    }
-    return clazz;
-  }
-
-  public static void renderPerformanceLog(String type, long time) {
-    if (WXEnvironment.isApkDebugable() || WXEnvironment.isPerf()) {
-//      builder.setLength(0);
-//      builder.append("[render time]").append(type).append(":").append(time);
-//      Log.d(WEEX_PERF_TAG, builder.substring(0));
-//      writeConsoleLog("debug", builder.substring(0));
-    }
-  }
-
-  private static void log(String tag, String msg, LogLevel level){
-    if(TextUtils.isEmpty(msg) || TextUtils.isEmpty(tag) || level == null || TextUtils.isEmpty(level.getName())){
-      return;
-    }
-    if (level == LogLevel.ERROR && !TextUtils.isEmpty(msg) && msg.contains("IPCException")){
-      WXStateRecord.getInstance().recordIPCException("ipc",msg);
-    }
-
-    if(sLogWatcher !=null){
-      sLogWatcher.onLog(level.getName(), tag, msg);
-    }
-
-    if (WXEnvironment.isApkDebugable()) {
-      if(level.getValue() - WXEnvironment.sLogLevel.getValue() >= 0) {
-        Log.println(level.getPriority(), tag, msg);
-        writeConsoleLog(level.getName(), msg);
-      }
-      // if not debug level then print log
-    }else {
-      if(level.getValue() - LogLevel.WARN.getValue() >=0 && level.getValue() - WXEnvironment.sLogLevel.getValue() >= 0){
-        Log.println(level.getPriority(),tag, msg);
-      }
-    }
-  }
-
-  public static void v(String msg) {
-    v(WEEX_TAG,msg);
-  }
-
-  public static void d(String msg) {
-    d(WEEX_TAG,msg);
-  }
-
-  public static void d(String tag, byte[] msg) {
-    d(tag, new String(msg));
-  }
-
-  public static void i(String msg) {
-    i(WEEX_TAG,msg);
-  }
-
-  public static void i(String tag, byte[] msg) {
-    i(tag, new String(msg));
-  }
-
-  public static void info(String msg) {
-    i(WEEX_TAG, msg);
-  }
-
-  public static void w(String msg) {
-    w(WEEX_TAG, msg);
-  }
-
-  public static void w(String tag, byte[] msg) {
-    w(tag, new String(msg));
-  }
-
-  public static void e(String msg) {
-    e(WEEX_TAG,msg);
-  }
-
-  public static void e(String tag, byte[] msg) {
-    e(tag, new String(msg));
-  }
-
-  public static void performance(String instanceId, byte[]msg) {
-//    String s = new String(msg);
-//    if(!TextUtils.isEmpty(instanceId)) {
-//      WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-//      if(sdkInstance != null) {
-//        int i = s.indexOf(",");
-//        if(i >=0 && i < s.length()) {
-//          String substring = s.substring(s.indexOf(",") + 1);
-//          LogDetail logDetail = JSON.parseObject(substring,LogDetail.class);
-//          sdkInstance.mTimeCalculator.addLog(logDetail);
-//        }
-//      }
-//    }
-//    Log.e(TIMELINE_TAG, "from WeexCore" + s);
-  }
-
-  public static void wtf(String msg){
-    wtf(WEEX_TAG, msg);
-  }
-
-  public static void d(String tag, String msg) {
-
-    if(!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(msg)){
-      log(tag, msg, LogLevel.DEBUG);
-
-      if(WXEnvironment.isApkDebugable()){//sLogLevel in debug mode is "LogLevel.DEBUG"
-        if ("jsLog".equals(tag) && jsLogWatcherList != null && jsLogWatcherList.size() > 0) {
-          for (JsLogWatcher jsLogWatcher : jsLogWatcherList) {
-            if (msg.endsWith("__DEBUG")) {
-              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__DEBUG", ""));
-            } else if (msg.endsWith("__INFO")) {
-              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__INFO", ""));
-            } else if (msg.endsWith("__WARN")) {
-              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__WARN", ""));
-            } else if (msg.endsWith("__ERROR")) {
-              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__ERROR", ""));
-            } else {
-              jsLogWatcher.onJsLog(Log.DEBUG, msg);
-            }
-          }
-        }
-      }
-    }
-  }
-
-  private static LogLevel getLogLevel(String level) {
-    switch (level.trim()){
-      case "__ERROR":
-        return LogLevel.ERROR;
-      case "__WARN":
-        return LogLevel.WARN;
-      case "__INFO":
-        return LogLevel.INFO;
-      case "__LOG":
-        return LogLevel.INFO;
-      case "__DEBUG":
-        return LogLevel.DEBUG;
-    }
-    return LogLevel.DEBUG;
-  }
-
-  public static void i(String tag, String msg) {
-    log(tag, msg,LogLevel.INFO);
-  }
-
-  public static void v(String tag, String msg) {
-    log(tag, msg,LogLevel.VERBOSE);
-  }
-
-  public static void w(String tag, String msg) {
-    log(tag, msg,LogLevel.WARN);
-  }
-
-  public static void e(String tag, String msg) {
-    log(tag, msg,LogLevel.ERROR);
-  }
-
-  public static void wtf(String tag, String msg){
-    log(tag, msg, LogLevel.WTF);
-  }
-
-  /**
-   * 'p' for 'Performance', use {@link #WEEX_PERF_TAG}
-   * @param msg
-   */
-  public static void p(String msg) {
-    d(WEEX_PERF_TAG,msg);
-  }
-
-  public static void d(String prefix, Throwable e) {
-    if (WXEnvironment.isApkDebugable()) {
-      d(prefix + getStackTrace(e));
-    }
-  }
-
-  public static void i(String prefix, Throwable e) {
-    if (WXEnvironment.isApkDebugable()) {
-      info(prefix + getStackTrace(e));
-    }
-  }
-
-  public static void v(String prefix, Throwable e) {
-    if (WXEnvironment.isApkDebugable()) {
-      v(prefix + getStackTrace(e));
-    }
-  }
-
-  public static void w(String prefix, Throwable e) {
-    w(prefix + getStackTrace(e));
-
-  }
-
-  public static void e(String prefix, Throwable e) {
-    e(prefix + getStackTrace(e));
-
-  }
-
-  public static void wtf(String prefix, Throwable e){
-    if (WXEnvironment.isApkDebugable()) {
-      wtf(prefix + getStackTrace(e));
-    }
-  }
-
-  /**
-   * 'p' for 'Performance', use {@link #WEEX_PERF_TAG}
-   */
-  public static void p(String prefix, Throwable e) {
-    if (WXEnvironment.isApkDebugable()) {
-      p(prefix + getStackTrace(e));
-    }
-  }
-
-  public static void eTag(String tag, Throwable e) {
-    if (WXEnvironment.isApkDebugable()) {
-      e(tag, getStackTrace(e));
-    }
-  }
-
-  public static String getStackTrace(@Nullable Throwable e) {
-    if (e == null) {
-      return "";
-    }
-    StringWriter sw = null;
-    PrintWriter pw = null;
-    try {
-      sw = new StringWriter();
-      pw = new PrintWriter(sw);
-      e.printStackTrace(pw);
-      pw.flush();
-      sw.flush();
-    } finally {
-      if (sw != null) {
-        try {
-          sw.close();
-        } catch (IOException e1) {
-          e1.printStackTrace();
-        }
-      }
-      if (pw != null) {
-        pw.close();
-      }
-    }
-    return sw.toString();
-  }
-
-
-
-  private static void writeConsoleLog(String level, String message) {
-    if (WXEnvironment.isApkDebugable()) {
-      try {
-        Class<?> clazz = clazzMaps.get(CLAZZ_NAME_LOG_UTIL);
-        if (clazz != null) {
-          Method m = clazz.getMethod("log", String.class, String.class);
-          m.invoke(clazz, level, message);
-        }
-      } catch (Exception e) {
-        Log.d(WEEX_TAG, "LogUtil not found!");
-      }
-    }
-  }
-
-  public static void setJsLogWatcher(JsLogWatcher watcher) {
-    if (!jsLogWatcherList.contains(watcher)) {
-      jsLogWatcherList.add(watcher);
-    }
-  }
-
-  public static void setLogWatcher(LogWatcher watcher) {
-    sLogWatcher = watcher;
-  }
-
-  public interface JsLogWatcher {
-    void onJsLog(int level, String log);
-  }
-
-  public interface LogWatcher {
-    void onLog(String level, String tag, String msg);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXMap.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXMap.java
deleted file mode 100644
index a3b6088..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXMap.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import java.io.Serializable;
-import java.util.HashMap;
-
-public class WXMap extends HashMap<String, String> implements Serializable {
-
-  public String put(String key, byte[] value) {
-    return super.put(key, new String(value));
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXReflectionUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXReflectionUtils.java
deleted file mode 100644
index 31ecd2f..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXReflectionUtils.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.text.TextUtils;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-
-public class WXReflectionUtils {
-
-  public static Object parseArgument(Type paramClazz, Object value) {
-    if(value != null){
-      if(value.getClass() == paramClazz){
-        return  value;
-      }
-      if(paramClazz instanceof  Class){
-        if( ((Class<?>) paramClazz).isAssignableFrom(value.getClass()))   {
-          return value;
-        }
-      }
-    }
-    if (paramClazz == String.class) {
-      return value instanceof String ? value : JSON.toJSONString(value);
-    } else if (paramClazz == int.class) {
-      return value.getClass().isAssignableFrom(int.class) ? value : WXUtils.getInt(value);
-    } else if (paramClazz == long.class) {
-      return value.getClass().isAssignableFrom(long.class) ? value : WXUtils.getLong(value);
-    } else if (paramClazz == double.class) {
-      return value.getClass().isAssignableFrom(double.class) ? value : WXUtils.getDouble(value);
-    } else if (paramClazz == float.class) {
-      return value.getClass().isAssignableFrom(float.class) ? value : WXUtils.getFloat(value);
-    } else if (paramClazz == JSONArray.class && value != null && value.getClass() == JSONArray.class) {
-      return  value;
-    } else if (paramClazz == JSONObject.class && value != null && value.getClass() == JSONObject.class) {
-      return  value;
-    } else {
-      return JSON.parseObject(value instanceof String ? (String) value : JSON.toJSONString(value), paramClazz);
-    }
-  }
-
-
-  public static void setValue(Object obj, String fieldName, Object value) {
-    if (obj == null || TextUtils.isEmpty(fieldName)) {
-      return;
-    }
-
-    try {
-      // Field field = obj.getClass().getDeclaredField(fieldName);
-      Field field = getDeclaredField(obj, fieldName);
-
-      Object realValue = value;
-      if (value instanceof BigDecimal || value instanceof Number || value instanceof String) {
-        if (field.getType() == Float.class || field.getType() == float.class) {
-          realValue = Float.parseFloat(value.toString());
-        } else if (field.getType() == Double.class || field.getType() == double.class) {
-          realValue = Double.parseDouble(value.toString());
-        } else if (field.getType() == Integer.class || field.getType() == int.class) {
-          realValue = (int) Double.parseDouble(value.toString());
-        } else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
-          realValue = Boolean.valueOf(value.toString());
-        }
-      }
-
-      if (field.getType() == boolean.class || field.getType() == Boolean.class) {
-        if (value != null) {
-          realValue = Boolean.valueOf(value.toString());
-        }
-      }
-
-      setProperty(obj, field, realValue);
-    } catch (Exception e) {
-      return;
-    }
-  }
-
-  /**
-   * get field form object and it's parent
-   */
-  public static Field getDeclaredField(Object object, String fieldName) {
-    Field field = null;
-
-    Class<?> clazz = object.getClass();
-
-    for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
-      try {
-        field = clazz.getDeclaredField(fieldName);
-        return field;
-      } catch (Exception e) {
-
-      }
-    }
-
-    return null;
-  }
-
-  /**
-   * Set property(field) of the specified object.
-   * @param bean The object which has the given property
-   * @param field The field to be set
-   * @param value The value to be set to the field
-   * @throws IllegalAccessException
-   * @throws InvocationTargetException
-   * @throws NoSuchMethodException
-   */
-  public static void setProperty(Object bean, Field field, Object value) throws IllegalAccessException,
-          InvocationTargetException,
-          NoSuchMethodException {
-
-    if (bean == null || field == null) {
-      return;
-    }
-
-    try {
-      field.setAccessible(true);
-      field.set(bean, value);
-    } catch (Exception e) {
-    }
-
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXResourceUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXResourceUtils.java
deleted file mode 100644
index c368689..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXResourceUtils.java
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Shader;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.util.Pair;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-/**
- * Class for parse color
- */
-public class WXResourceUtils {
-
-  private final static Map<String, Integer> colorMap = new HashMap<>();
-  private final static int RGB_SIZE = 3;
-  private final static int RGBA_SIZE = 4;
-  private final static int HEX = 16;
-  private final static int COLOR_RANGE = 255;
-  private final static String RGB = "rgb";
-  private final static String RGBA = "rgba";
-  private final static SingleFunctionParser.FlatMapper<Integer> FUNCTIONAL_RGB_MAPPER =
-          new SingleFunctionParser.FlatMapper<Integer>() {
-            @Override
-            public Integer map(String raw) {
-              int color = WXUtils.parseUnitOrPercent(raw, COLOR_RANGE);
-              if (color < 0) {
-                color = 0;
-              } else if (color > COLOR_RANGE) {
-                color = COLOR_RANGE;
-              }
-              return color;
-            }
-          };
-
-  private final static SingleFunctionParser.NonUniformMapper<Number> FUNCTIONAL_RGBA_MAPPER =
-          new SingleFunctionParser.NonUniformMapper<Number>() {
-            @Override
-            public List<Number> map(List<String> raw) {
-              List<Number> result = new ArrayList<>(RGBA_SIZE);
-              int i, color;
-              for (i = 0; i < RGB_SIZE; i++) {
-                color = WXUtils.parseUnitOrPercent(raw.get(i), COLOR_RANGE);
-                if (color < 0) {
-                  color = 0;
-                } else if (color > COLOR_RANGE) {
-                  color = COLOR_RANGE;
-                }
-                result.add(color);
-              }
-              result.add(Float.valueOf(raw.get(i)));
-              return result;
-            }
-          };
-
-  static {
-    colorMap.put("aliceblue", 0XFFF0F8FF);
-    colorMap.put("antiquewhite", 0XFFFAEBD7);
-    colorMap.put("aqua", 0XFF00FFFF);
-    colorMap.put("aquamarine", 0XFF7FFFD4);
-    colorMap.put("azure", 0XFFF0FFFF);
-    colorMap.put("beige", 0XFFF5F5DC);
-    colorMap.put("bisque", 0XFFFFE4C4);
-    colorMap.put("black", 0XFF000000);
-    colorMap.put("blanchedalmond", 0XFFFFEBCD);
-    colorMap.put("blue", 0XFF0000FF);
-    colorMap.put("blueviolet", 0XFF8A2BE2);
-    colorMap.put("brown", 0XFFA52A2A);
-    colorMap.put("burlywood", 0XFFDEB887);
-    colorMap.put("cadetblue", 0XFF5F9EA0);
-    colorMap.put("chartreuse", 0XFF7FFF00);
-    colorMap.put("chocolate", 0XFFD2691E);
-    colorMap.put("coral", 0XFFFF7F50);
-    colorMap.put("cornflowerblue", 0XFF6495ED);
-    colorMap.put("cornsilk", 0XFFFFF8DC);
-    colorMap.put("crimson", 0XFFDC143C);
-    colorMap.put("cyan", 0XFF00FFFF);
-    colorMap.put("darkblue", 0XFF00008B);
-    colorMap.put("darkcyan", 0XFF008B8B);
-    colorMap.put("darkgoldenrod", 0XFFB8860B);
-    colorMap.put("darkgray", 0XFFA9A9A9);
-    colorMap.put("darkgreen", 0XFF006400);
-    colorMap.put("darkkhaki", 0XFFBDB76B);
-    colorMap.put("darkmagenta", 0XFF8B008B);
-    colorMap.put("darkolivegreen", 0XFF556B2F);
-    colorMap.put("darkorange", 0XFFFF8C00);
-    colorMap.put("darkorchid", 0XFF9932CC);
-    colorMap.put("darkred", 0XFF8B0000);
-    colorMap.put("darksalmon", 0XFFE9967A);
-    colorMap.put("darkseagreen", 0XFF8FBC8F);
-    colorMap.put("darkslateblue", 0XFF483D8B);
-    colorMap.put("darkslategray", 0XFF2F4F4F);
-    colorMap.put("darkslategrey", 0XFF2F4F4F);
-    colorMap.put("darkturquoise", 0XFF00CED1);
-    colorMap.put("darkviolet", 0XFF9400D3);
-    colorMap.put("deeppink", 0XFFFF1493);
-    colorMap.put("deepskyblue", 0XFF00BFFF);
-    colorMap.put("dimgray", 0XFF696969);
-    colorMap.put("dimgrey", 0XFF696969);
-    colorMap.put("dodgerblue", 0XFF1E90FF);
-    colorMap.put("firebrick", 0XFFB22222);
-    colorMap.put("floralwhite", 0XFFFFFAF0);
-    colorMap.put("forestgreen", 0XFF228B22);
-    colorMap.put("fuchsia", 0XFFFF00FF);
-    colorMap.put("gainsboro", 0XFFDCDCDC);
-    colorMap.put("ghostwhite", 0XFFF8F8FF);
-    colorMap.put("gold", 0XFFFFD700);
-    colorMap.put("goldenrod", 0XFFDAA520);
-    colorMap.put("gray", 0XFF808080);
-    colorMap.put("grey", 0XFF808080);
-    colorMap.put("green", 0XFF008000);
-    colorMap.put("greenyellow", 0XFFADFF2F);
-    colorMap.put("honeydew", 0XFFF0FFF0);
-    colorMap.put("hotpink", 0XFFFF69B4);
-    colorMap.put("indianred", 0XFFCD5C5C);
-    colorMap.put("indigo", 0XFF4B0082);
-    colorMap.put("ivory", 0XFFFFFFF0);
-    colorMap.put("khaki", 0XFFF0E68C);
-    colorMap.put("lavender", 0XFFE6E6FA);
-    colorMap.put("lavenderblush", 0XFFFFF0F5);
-    colorMap.put("lawngreen", 0XFF7CFC00);
-    colorMap.put("lemonchiffon", 0XFFFFFACD);
-    colorMap.put("lightblue", 0XFFADD8E6);
-    colorMap.put("lightcoral", 0XFFF08080);
-    colorMap.put("lightcyan", 0XFFE0FFFF);
-    colorMap.put("lightgoldenrodyellow", 0XFFFAFAD2);
-    colorMap.put("lightgray", 0XFFD3D3D3);
-    colorMap.put("lightgrey", 0XFFD3D3D3);
-    colorMap.put("lightgreen", 0XFF90EE90);
-    colorMap.put("lightpink", 0XFFFFB6C1);
-    colorMap.put("lightsalmon", 0XFFFFA07A);
-    colorMap.put("lightseagreen", 0XFF20B2AA);
-    colorMap.put("lightskyblue", 0XFF87CEFA);
-    colorMap.put("lightslategray", 0XFF778899);
-    colorMap.put("lightslategrey", 0XFF778899);
-    colorMap.put("lightsteelblue", 0XFFB0C4DE);
-    colorMap.put("lightyellow", 0XFFFFFFE0);
-    colorMap.put("lime", 0XFF00FF00);
-    colorMap.put("limegreen", 0XFF32CD32);
-    colorMap.put("linen", 0XFFFAF0E6);
-    colorMap.put("magenta", 0XFFFF00FF);
-    colorMap.put("maroon", 0XFF800000);
-    colorMap.put("mediumaquamarine", 0XFF66CDAA);
-    colorMap.put("mediumblue", 0XFF0000CD);
-    colorMap.put("mediumorchid", 0XFFBA55D3);
-    colorMap.put("mediumpurple", 0XFF9370DB);
-    colorMap.put("mediumseagreen", 0XFF3CB371);
-    colorMap.put("mediumslateblue", 0XFF7B68EE);
-    colorMap.put("mediumspringgreen", 0XFF00FA9A);
-    colorMap.put("mediumturquoise", 0XFF48D1CC);
-    colorMap.put("mediumvioletred", 0XFFC71585);
-    colorMap.put("midnightblue", 0XFF191970);
-    colorMap.put("mintcream", 0XFFF5FFFA);
-    colorMap.put("mistyrose", 0XFFFFE4E1);
-    colorMap.put("moccasin", 0XFFFFE4B5);
-    colorMap.put("navajowhite", 0XFFFFDEAD);
-    colorMap.put("navy", 0XFF000080);
-    colorMap.put("oldlace", 0XFFFDF5E6);
-    colorMap.put("olive", 0XFF808000);
-    colorMap.put("olivedrab", 0XFF6B8E23);
-    colorMap.put("orange", 0XFFFFA500);
-    colorMap.put("orangered", 0XFFFF4500);
-    colorMap.put("orchid", 0XFFDA70D6);
-    colorMap.put("palegoldenrod", 0XFFEEE8AA);
-    colorMap.put("palegreen", 0XFF98FB98);
-    colorMap.put("paleturquoise", 0XFFAFEEEE);
-    colorMap.put("palevioletred", 0XFFDB7093);
-    colorMap.put("papayawhip", 0XFFFFEFD5);
-    colorMap.put("peachpuff", 0XFFFFDAB9);
-    colorMap.put("peru", 0XFFCD853F);
-    colorMap.put("pink", 0XFFFFC0CB);
-    colorMap.put("plum", 0XFFDDA0DD);
-    colorMap.put("powderblue", 0XFFB0E0E6);
-    colorMap.put("purple", 0XFF800080);
-    colorMap.put("rebeccapurple", 0XFF663399);
-    colorMap.put("red", 0XFFFF0000);
-    colorMap.put("rosybrown", 0XFFBC8F8F);
-    colorMap.put("royalblue", 0XFF4169E1);
-    colorMap.put("saddlebrown", 0XFF8B4513);
-    colorMap.put("salmon", 0XFFFA8072);
-    colorMap.put("sandybrown", 0XFFF4A460);
-    colorMap.put("seagreen", 0XFF2E8B57);
-    colorMap.put("seashell", 0XFFFFF5EE);
-    colorMap.put("sienna", 0XFFA0522D);
-    colorMap.put("silver", 0XFFC0C0C0);
-    colorMap.put("skyblue", 0XFF87CEEB);
-    colorMap.put("slateblue", 0XFF6A5ACD);
-    colorMap.put("slategray", 0XFF708090);
-    colorMap.put("slategrey", 0XFF708090);
-    colorMap.put("snow", 0XFFFFFAFA);
-    colorMap.put("springgreen", 0XFF00FF7F);
-    colorMap.put("steelblue", 0XFF4682B4);
-    colorMap.put("tan", 0XFFD2B48C);
-    colorMap.put("teal", 0XFF008080);
-    colorMap.put("thistle", 0XFFD8BFD8);
-    colorMap.put("tomato", 0XFFFF6347);
-    colorMap.put("turquoise", 0XFF40E0D0);
-    colorMap.put("violet", 0XFFEE82EE);
-    colorMap.put("wheat", 0XFFF5DEB3);
-    colorMap.put("white", 0XFFFFFFFF);
-    colorMap.put("whitesmoke", 0XFFF5F5F5);
-    colorMap.put("yellow", 0XFFFFFF00);
-    colorMap.put("yellowgreen", 0XFF9ACD32);
-    colorMap.put("transparent", 0x00000000);
-  }
-
-  public static int getColor(String color) {
-    return getColor(color, Integer.MIN_VALUE);
-  }
-
-  public static int getColor(String color, int defaultColor) {
-    if (TextUtils.isEmpty(color)) {
-      return defaultColor;
-    }
-    color = color.trim(); //remove non visible codes
-
-    Integer cache = WXUtils.sCache.get(color);
-    if(cache!=null){
-      return cache;
-    }
-    else {
-      int resultColor = defaultColor;
-      Pair<Boolean, Integer> result;
-      ColorConvertHandler[] handlers = ColorConvertHandler.values();
-      for (ColorConvertHandler handler : handlers) {
-        try {
-          result = handler.handle(color);
-          if (result.first) {
-            resultColor = result.second;
-            WXUtils.sCache.put(color, resultColor);
-            break;
-          }
-        } catch (RuntimeException e) {
-          WXLogUtils.v("Color_Parser", WXLogUtils.getStackTrace(e));
-        }
-      }
-      return resultColor;
-    }
-  }
-
-  /**
-   * Assembly gradients
-   * @param image gradient values contains direction、colors
-   * @param width component width
-   * @param height component height
-   * @return gradient shader
-   */
-  public static Shader getShader(String image, float width, float height) {
-    List<String> valueList = parseGradientValues(image);
-    if (valueList != null && valueList.size() == 3) {
-      float[] points = parseGradientDirection(valueList.get(0), width, height);
-      Shader shader = new LinearGradient(points[0], points[1],
-              points[2], points[3],
-              getColor(valueList.get(1), Color.WHITE), getColor(valueList.get(2), Color.WHITE),
-              Shader.TileMode.CLAMP);
-      return shader;
-    }
-    return null;
-  }
-
-  /**
-   * parse gradient values contains direction、colors
-   * @param image gradient values
-   * @return split values by comma
-   */
-  @NonNull
-  private static List<String> parseGradientValues(String image) {
-    if (TextUtils.isEmpty(image)) {
-      return null;
-    }
-    image.trim();
-    if(image.startsWith("linear-gradient")){
-      String valueStr = image.substring(image.indexOf("(") + 1, image.lastIndexOf(")"));
-      StringTokenizer tokenizer = new StringTokenizer(valueStr, ",");
-      List<String> values = new ArrayList<>();
-      String temp = null;
-      while (tokenizer.hasMoreTokens()) {
-        String token = tokenizer.nextToken();
-        if (token.contains("(")) {
-          temp = token + ",";
-          continue;
-        }
-        if (token.contains(")")) {
-          temp += token;
-          values.add(temp);
-          temp = null;
-          continue;
-        }
-        if (temp != null) {
-          temp += (token + ",");
-          continue;
-        }
-        values.add(token);
-      }
-      return values;
-    }
-    return null;
-  }
-
-  /**
-   * parse gradient direction
-   * @param direction gradient direction
-   * @param width component width
-   * @param height component height
-   * @return gradient points
-   */
-  private static float[] parseGradientDirection(String direction, float width, float height) {
-    int x1 = 0, y1 = 1, x2 = 2, y2 = 3;
-    float[] points = {0, 0, 0, 0};
-
-    if (!TextUtils.isEmpty(direction)) {
-      direction = direction.replaceAll("\\s*", "").toLowerCase(Locale.ROOT);
-    }
-
-    switch (direction) {
-      //to right
-      case "toright":
-        points[x2] = width;
-        break;
-      //to left
-      case "toleft":
-        points[x1] = width;
-        break;
-      //to bottom
-      case "tobottom":
-        points[y2] = height;
-        break;
-      //to top
-      case "totop":
-        points[y1] = height;
-        break;
-      //to bottom right
-      case "tobottomright":
-        points[x2] = width;
-        points[y2] = height;
-        break;
-      //to top left
-      case "totopleft":
-        points[x1] = width;
-        points[y1] = height;
-        break;
-    }
-    return points;
-  }
-
-  public static boolean isNamedColor(String name) {
-    return colorMap.containsKey(name);
-  }
-
-  enum ColorConvertHandler {
-    NAMED_COLOR_HANDLER {
-      @Override
-      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
-        if (colorMap.containsKey(rawColor)) {
-          return new Pair<>(Boolean.TRUE, colorMap.get(rawColor));
-        } else {
-          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
-        }
-      }
-    },
-    RGB_HANDLER {
-      @Override
-      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
-        if (rawColor.length() == 4) {
-          //#eee, #333
-          int r, g, b;
-          r = Integer.parseInt(rawColor.substring(1, 2), HEX);
-          g = Integer.parseInt(rawColor.substring(2, 3), HEX);
-          b = Integer.parseInt(rawColor.substring(3, 4), HEX);
-          return new Pair<>(Boolean.TRUE, Color.rgb(r + (r << 4), g + (g << 4), b + (b << 4)));
-        } else if (rawColor.length() == 7 || rawColor.length() == 9) {
-          //#eeeeee, #333333
-          return new Pair<>(Boolean.TRUE, Color.parseColor(rawColor));
-        } else {
-          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
-        }
-      }
-    },
-    FUNCTIONAL_RGB_HANDLER {
-      @Override
-      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
-        SingleFunctionParser<Integer> functionParser = new SingleFunctionParser<>(rawColor, FUNCTIONAL_RGB_MAPPER);
-        List<Integer> rgb = functionParser.parse(RGB);
-        if (null != rgb && rgb.size() == RGB_SIZE) {
-          return new Pair<>(Boolean.TRUE, Color.rgb(rgb.get(0), rgb.get(1), rgb.get(2)));
-        } else {
-          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
-        }
-      }
-    },
-
-    FUNCTIONAL_RGBA_HANDLER {
-      @Override
-      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
-        SingleFunctionParser<Number> functionParser = new SingleFunctionParser<>(rawColor, FUNCTIONAL_RGBA_MAPPER);
-        List<Number> rgba = functionParser.parse(RGBA);
-        if (rgba.size() == RGBA_SIZE) {
-          return new Pair<>(Boolean.TRUE, Color.argb(
-                  parseAlpha(rgba.get(3).floatValue()),
-                  rgba.get(0).intValue(),
-                  rgba.get(1).intValue(),
-                  rgba.get(2).intValue()));
-        } else {
-          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
-        }
-      }
-    };
-
-    /**
-     * Parse color to #RRGGBB or #AARRGGBB. The parsing algorithm depends on sub-class.
-     *
-     * @param rawColor color, maybe functional RGB(RGBA), #RGB, keywords color or transparent
-     * @return #RRGGBB or #AARRGGBB
-     */
-    @NonNull abstract Pair<Boolean, Integer> handle(String rawColor);
-
-    /**
-     * Parse alpha gradient of color from range 0-1 to range 0-255
-     *
-     * @param alpha the alpha value, in range 0-1
-     * @return the alpha value, in range 0-255
-     */
-    private static int parseAlpha(float alpha) {
-      return (int) (alpha * COLOR_RANGE);
-    }
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXSoInstallMgrSdk.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXSoInstallMgrSdk.java
deleted file mode 100644
index 35a3086..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXSoInstallMgrSdk.java
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.annotation.SuppressLint;
-import android.app.Application;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.os.Build;
-import android.text.TextUtils;
-import com.taobao.weex.IWXStatisticsListener;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.adapter.IWXSoLoaderAdapter;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
-import com.taobao.weex.common.WXErrorCode;
-import dalvik.system.PathClassLoader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.Enumeration;
-import java.util.Locale;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
-
-
-/**
- * Utility class for managing so library, including load native library and version management.
- * <ol>
- *   <li>Load library<br>
- *     It Will try to use {@link System#loadLibrary(String)} to load native library. If it successes,
- *     the Android Framework will be responsible for managing library and library version.
- *     If it fails in case of some ceratin armebi-v7a architecture device, it will try to extract
- *     native library from apk and copy it the data directory of the app. Then load it using
- *     {@link System#load(String)}.
- *     </li>
- *  <li>
- *       Version control for extracting native library from apk.
- *  </li>
- * </ol>
- */
-public class WXSoInstallMgrSdk {
-
-  final static String LOGTAG = "INIT_SO";
-  //below is the CPU string types
-  private final static String ARMEABI = "armeabi"; //default
-  private final static String X86 = "x86";
-  private final static String MIPS = "mips";
-  private final static String STARTUPSO = "/libweexjsb.so";
-  private final static String STARTUPSOANDROID15 = "/libweexjst.so";
-
-  static Application mContext = null;
-  private static IWXSoLoaderAdapter mSoLoader = null;
-  private static IWXStatisticsListener mStatisticsListener = null;
-
-  private static String mAbi = null;
-
-  public static void init(Application c,
-                          IWXSoLoaderAdapter loader,
-                          IWXStatisticsListener listener) {
-    mContext = c;
-    mSoLoader = loader;
-    mStatisticsListener = listener;
-  }
-
-  public static boolean isX86(){
-    String cpuType = _cpuType();
-    return cpuType.equalsIgnoreCase(X86);
-  }
-
-  public static boolean isCPUSupport(){
-    String cpuType = _cpuType();
-    return !cpuType.equalsIgnoreCase(MIPS);
-  }
-
-  /**
-   * Load so library.
-   *
-   * If a library loader adapter exists, use this adapter to load library,
-   * otherwise use {@link System#loadLibrary(String)} to load library.
-   * If failed to load library, try to extract the so library and load it
-   * from arembi in the .apk
-   *
-   * @param libName library name, like webp, not necessary to be libwep.so
-   * @param version the version of the so library
-   */
-  public static boolean initSo(String libName, int version, IWXUserTrackAdapter utAdapter) {
-    String cpuType = _cpuType();
-    if (cpuType.equalsIgnoreCase(MIPS) ) {
-      WXExceptionUtils.commitCriticalExceptionRT(null,
-              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
-              "initSo", "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for android cpuType is MIPS",
-              null);
-      return false;
-    }
-
-    // copy startup so
-    if (WXEnvironment.CORE_SO_NAME.equals(libName)) {
-      copyStartUpSo();
-    }
-
-
-    boolean InitSuc = false;
-      try {
-        // If a library loader adapter exists, use this adapter to load library
-        // instead of System.loadLibrary.
-        if (mSoLoader != null) {
-          mSoLoader.doLoadLibrary("c++_shared");
-        } else {
-          System.loadLibrary("c++_shared");
-        }
-      } catch (Exception | Error e) {
-        WXExceptionUtils.commitCriticalExceptionRT(null,
-                WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
-                "initSo",
-                        "load c++_shared failed Detail Error is: " +e.getMessage(),
-                null);
-
-        if(WXEnvironment.isApkDebugable()) {
-          throw e;
-        }
-      }
-
-      /**
-       * Load library with {@link System#loadLibrary(String)}
-       */
-      try {
-        // If a library loader adapter exists, use this adapter to load library
-        // instead of System.loadLibrary.
-        if (mSoLoader != null) {
-          mSoLoader.doLoadLibrary(libName);
-        } else {
-          System.loadLibrary(libName);
-        }
-
-        InitSuc = true;
-      } catch (Exception | Error e2) {
-        if (cpuType.contains(ARMEABI) || cpuType.contains(X86)) {
-          WXExceptionUtils.commitCriticalExceptionRT(null,
-                  WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
-                  "initSo", libName + "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for android cpuType is " +cpuType +
-                          "\n Detail Error is: " +e2.getMessage(),
-                  null);
-        }
-
-        if(WXEnvironment.isApkDebugable()) {
-          throw e2;
-        }
-        InitSuc = false;
-      }
-
-//      try {
-
-//        if (!InitSuc) {
-//
-//          //File extracted from apk already exists.
-//          if (isExist(libName, version)) {
-//            boolean res = _loadUnzipSo(libName, version, utAdapter);
-//            if (res) {
-//              return res;
-//            } else {
-//              //Delete the corrupt so library, and extract it again.
-//              removeSoIfExit(libName, version);
-//            }
-//          }
-//
-//          //Fail for loading file from libs, extract so library from so and load it.
-//          if (cpuType.equalsIgnoreCase(MIPS)) {
-//            return false;
-//          } else {
-//            try {
-//              InitSuc = unZipSelectedFiles(libName, version, utAdapter);
-//            } catch (IOException e2) {
-//              e2.printStackTrace();
-//            }
-//          }
-//
-//        }
-//      } catch (Exception | Error e) {
-//        InitSuc = false;
-//        e.printStackTrace();
-//      }
-  //  }
-    return InitSuc;
-  }
-
-  private static File _desSoCopyFile(String soName) {
-    String cpuType = _cpuType();
-    String copyPath = WXEnvironment.copySoDesDir();
-    if (TextUtils.isEmpty(copyPath)) {
-      return null;
-    }
-    File desDir = new File(copyPath, soName + "/" + cpuType);
-    return desDir;
-  }
-
-  /**
-   * copyStartUpSo
-   */
-  @SuppressLint("SdCardPath")
-  public static void copyStartUpSo() {
-    try {
-      // copy libjsb.so to cache/weex/jsb/cputype
-      String pkgName = WXEnvironment.getApplication().getPackageName();
-      String cacheFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
-
-      // cp weexjsb any way
-      // if android api < 16 copy libweexjst.so else copy libweexjsb.so
-      boolean pieSupport = true;
-      File newfile;
-      String startSoName = WXEnvironment.CORE_JSB_SO_NAME;
-      String startSoPath = STARTUPSO;
-      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
-        pieSupport = false;
-        startSoName = WXEnvironment.CORE_JST_SO_NAME;
-        startSoPath = STARTUPSOANDROID15;
-      }
-
-      final File copyPath = _desSoCopyFile(startSoName);
-      if(!copyPath.exists()) {
-        copyPath.mkdirs();
-      }
-      newfile = new File(copyPath, startSoPath);
-      WXEnvironment.CORE_JSB_SO_PATH = newfile.getAbsolutePath();
-      String jsb = WXEnvironment.getDefaultSettingValue(startSoName, "-1");
-      if(newfile.exists() && TextUtils.equals(WXEnvironment.getAppVersionName(), jsb)) {
-        // no update so skip copy
-        return;
-      }
-
-      String path = "/data/data/" + pkgName + "/lib";
-      if (cacheFile != null && cacheFile.indexOf("/cache") > 0) {
-        path = cacheFile.replace("/cache", "/lib");
-      }
-      File oldfile = null;
-      if (pieSupport) {
-        oldfile = new File(path, STARTUPSO);
-      } else {
-        oldfile = new File(path , STARTUPSOANDROID15);
-      }
-
-
-      if (!oldfile.exists()) {
-        try {
-          String weexjsb = ((PathClassLoader) (WXSoInstallMgrSdk.class.getClassLoader())).findLibrary(startSoName);
-          oldfile = new File(weexjsb);
-        } catch (Throwable throwable) {
-          // do nothing
-        }
-      }
-
-
-      if(!oldfile.exists()) {
-        WXEnvironment.extractSo();
-        oldfile = new File(copyPath, STARTUPSO);
-      }
-
-      if (oldfile.exists()) {
-        WXFileUtils.copyFile(oldfile, newfile);
-      }
-      WXEnvironment.writeDefaultSettingsValue(startSoName, WXEnvironment.getAppVersionName());
-    } catch (Throwable e) {
-      e.printStackTrace();
-    }
-  }
-
-  public static void copyJssRuntimeSo(){
-    boolean tryUseRunTimeApi = WXUtils.checkGreyConfig("wxapm","use_runtime_api","0");
-    WXLogUtils.e("weex", "tryUseRunTimeApi ? "+ tryUseRunTimeApi);
-    if (!tryUseRunTimeApi){
-      return;
-    }
-    try {
-      WXLogUtils.e("weex", "copyJssRuntimeSo: ");
-      File toPath = _desSoCopyFile(WXEnvironment.CORE_JSS_SO_NAME);
-      if(!toPath.exists()) {
-        toPath.mkdirs();
-      }
-      File targetFile = new File(toPath,"libweexjss.so");
-
-      /** 1. check so and versionCode. if update, then rm old jss.so(runtime) in pkg/libs, and copy new so from apk **/
-      String keyVersionCode = "app_version_code_weex";
-      String defaultSettingValue = WXEnvironment.getDefaultSettingValue(keyVersionCode, "-1");
-
-
-      if (targetFile.exists()){
-        if (!TextUtils.equals(WXEnvironment.getAppVersionName(),defaultSettingValue)){
-          targetFile.delete();
-        }else {
-          WXEnvironment.CORE_JSS_RUNTIME_SO_PATH= targetFile.getAbsolutePath();
-          WXEnvironment.sUseRunTimeApi = true;
-          WXLogUtils.e("weex", "copyJssRuntimeSo exist:  return");
-          return;
-        }
-      }
-      /** 2. copy jss(runtime) so **/
-      String fromPath =  ((PathClassLoader) (WXSoInstallMgrSdk.class.getClassLoader())).findLibrary("weexjssr");
-      if (TextUtils.isEmpty(fromPath)){
-        return;
-      }
-      targetFile.createNewFile();
-      WXFileUtils.copyFileWithException(new File(fromPath),targetFile);
-      /**3. update flag **/
-      WXEnvironment.CORE_JSS_RUNTIME_SO_PATH= targetFile.getAbsolutePath();
-      WXEnvironment.writeDefaultSettingsValue(keyVersionCode,WXEnvironment.getAppVersionName());
-      WXEnvironment.sUseRunTimeApi = true;
-      WXLogUtils.e("weex", "copyJssRuntimeSo: cp end and return ");
-    }catch (Throwable e){
-      e.printStackTrace();
-      WXEnvironment.sUseRunTimeApi = false;
-      WXLogUtils.e("weex", "copyJssRuntimeSo:  exception" + e);
-    }
-  }
-
-  private static String _getFieldReflectively(Build build, String fieldName) {
-    try {
-      final Field field = Build.class.getField(fieldName);
-      return field.get(build).toString();
-    } catch (Exception ex) {
-      return "Unknown";
-    }
-  }
-
-  private static String _cpuType() {
-    if(TextUtils.isEmpty(mAbi)) {
-      try {
-        mAbi = Build.CPU_ABI;
-      }catch (Throwable e){
-        e.printStackTrace();
-        mAbi = ARMEABI;
-      }
-      if (TextUtils.isEmpty(mAbi)){
-        mAbi = ARMEABI;
-      }
-      mAbi = mAbi.toLowerCase(Locale.ROOT);
-    }
-    return mAbi;
-  }
-
-  /**
-   *
-   * @param libName lib name
-   * @param size  the right size of lib
-   * @return true for valid  ; false for InValid
-   */
-  static boolean checkSoIsValid(String libName, long size) {
-    Context context = mContext;
-    if (null == context) {
-      return false;
-    }
-    try{
-      long start=System.currentTimeMillis();
-      if(WXSoInstallMgrSdk.class.getClassLoader() instanceof PathClassLoader ) {
-
-        String path = ((PathClassLoader) (WXSoInstallMgrSdk.class.getClassLoader())).findLibrary(libName);
-        if(TextUtils.isEmpty(path) ){
-          return false;
-        }
-        File file = new File(path);
-
-        if (!file.exists() || size == file.length()) {
-          WXLogUtils.w("weex so size check path :" + path+"   "+(System.currentTimeMillis() - start));
-          return true;
-        } else {
-          return false;
-        }
-      }
-    }catch(Throwable e ){
-      WXExceptionUtils.commitCriticalExceptionRT(null,
-              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
-              "checkSoIsValid", "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for " +
-                      "weex so size check fail exception :"+e.getMessage(),
-              null);
-      WXLogUtils.e("weex so size check fail exception :"+e.getMessage());
-    }
-
-    return true;
-  }
-
-  /**
-   * Concatenate the path of the so library, including directory.
-   * @param libName the raw name of the lib
-   * @param version the version of the so library
-   * @return the path of the so library
-   */
-  @SuppressLint("SdCardPath")
-  static String _targetSoFile(String libName, int version) {
-    Context context = mContext;
-    if (null == context) {
-      return "";
-    }
-
-    String path = "/data/data/" + context.getPackageName() + "/files";
-
-    File f = context.getFilesDir();
-    if (f != null) {
-      path = f.getPath();
-    }
-    return path + "/lib" + libName + "bk" + version + ".so";
-
-  }
-
-  /**
-   * Remove the so library if it had been extracted.
-   * @param libName
-   * @param version
-   */
-  static void removeSoIfExit(String libName, int version) {
-
-    String file = _targetSoFile(libName, version);
-    File a = new File(file);
-    if (a.exists()) {
-      a.delete();
-    }
-
-  }
-
-  /**
-   * Tell whether the so is extracted.
-   */
-  static boolean isExist(String libName, int version) {
-
-    String file = _targetSoFile(libName, version);
-    File a = new File(file);
-    return a.exists();
-
-  }
-
-
-  /**
-   * Load .so library
-   */
-  @SuppressLint("UnsafeDynamicallyLoadedCode")
-  static boolean _loadUnzipSo(String libName,
-                              int version,
-                              IWXUserTrackAdapter utAdapter) {
-    boolean initSuc = false;
-    try {
-      if (isExist(libName, version)) {
-        // If a library loader adapter exists, use this adapter to load library
-        // instead of System.load.
-        if (mSoLoader != null) {
-          mSoLoader.doLoad(_targetSoFile(libName, version));
-        } else {
-          System.load(_targetSoFile(libName, version));
-        }
-      }
-      initSuc = true;
-    } catch (Throwable e) {
-      initSuc = false;
-      WXExceptionUtils.commitCriticalExceptionRT(null,
-              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT,
-              "_loadUnzipSo", "[WX_KEY_EXCEPTION_SDK_INIT_WX_ERR_COPY_FROM_APK] " +
-                      "\n Detail Msg is : " +  e.getMessage(),
-              null);
-      WXLogUtils.e("", e);
-    }
-    return initSuc;
-  }
-
-  static boolean unZipSelectedFiles(String libName,
-                                    int version,
-                                    IWXUserTrackAdapter utAdapter) throws ZipException, IOException {
-    String sourcePath = "lib/armeabi/lib" + libName + ".so";
-
-    String zipPath = "";
-    Context context = mContext;
-    if (context == null) {
-      return false;
-    }
-
-    ApplicationInfo aInfo = context.getApplicationInfo();
-    if (null != aInfo) {
-      zipPath = aInfo.sourceDir;
-    }
-
-    ZipFile zf;
-    zf = new ZipFile(zipPath);
-    try {
-
-      for (Enumeration<?> entries = zf.entries(); entries.hasMoreElements(); ) {
-        ZipEntry entry = ((ZipEntry) entries.nextElement());
-        if (entry.getName().startsWith(sourcePath)) {
-
-          InputStream in = null;
-          FileOutputStream os = null;
-          FileChannel channel = null;
-          int total = 0;
-          try {
-
-            //Make sure the old library is deleted.
-            removeSoIfExit(libName, version);
-
-            //Copy file
-            in = zf.getInputStream(entry);
-            os = context.openFileOutput("lib" + libName + "bk" + version + ".so",
-                    Context.MODE_PRIVATE);
-            channel = os.getChannel();
-
-            byte[] buffers = new byte[1024];
-            int realLength;
-
-            while ((realLength = in.read(buffers)) > 0) {
-              //os.write(buffers);
-              channel.write(ByteBuffer.wrap(buffers, 0, realLength));
-              total += realLength;
-
-            }
-          } finally {
-            if (in != null) {
-              try {
-                in.close();
-              } catch (Exception e) {
-                e.printStackTrace();
-              }
-            }
-
-            if (channel != null) {
-              try {
-                channel.close();
-              } catch (Exception e) {
-                e.printStackTrace();
-              }
-            }
-
-            if (os != null) {
-              try {
-                os.close();
-              } catch (Exception e) {
-                e.printStackTrace();
-              }
-            }
-
-            if (zf != null) {
-              zf.close();
-              zf = null;
-            }
-          }
-
-          if (total > 0) {
-            return _loadUnzipSo(libName, version, utAdapter);
-          } else {
-            return false;
-          }
-        }
-      }
-    } catch (java.io.IOException e) {
-      e.printStackTrace();
-      WXExceptionUtils.commitCriticalExceptionRT(null,
-              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT,
-              "unZipSelectedFiles", "[WX_KEY_EXCEPTION_SDK_INIT_unZipSelectedFiles] " +
-                      "\n Detail msg is: " + e.getMessage(),
-              null);
-
-    } finally {
-
-      if (zf != null) {
-        zf.close();
-        zf = null;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Using {@Code WXExceptionUtils.commitCriticalExceptionRT}  insted
-   */
-//  static void commit(IWXUserTrackAdapter utAdapter, String errCode, String errMsg) {
-//    if (mStatisticsListener != null) {
-//      mStatisticsListener.onException("0", errCode, errMsg);
-//    }
-//
-//    if (utAdapter == null) {
-//      return;
-//    }
-//    if (errCode != null && errMsg != null) {
-//      WXPerformance p = new WXPerformance();
-//      p.errCode = errCode;
-//      p.errMsg = errMsg;
-//      utAdapter.commit(null, null, WXEnvironment.ENVIRONMENT, p, null);
-//    } else {
-//      utAdapter.commit(null, null, WXEnvironment.ENVIRONMENT, null, null);
-//
-//    }
-//  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXUtils.java
deleted file mode 100644
index 95bdfae..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXUtils.java
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.support.annotation.Nullable;
-import android.support.v4.util.LruCache;
-import android.text.TextUtils;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.adapter.IWXConfigAdapter;
-import com.taobao.weex.common.Constants;
-
-public class WXUtils {
-
-  final static LruCache<String, Integer> sCache = new LruCache<>(64);
-  public static final char PERCENT = '%';
-  private static final int HUNDRED =100;
-  /**
-   * Tell whether current thread is UI(main) thread.
-   * @return true for UI(main) thread
-   */
-  public static boolean isUiThread() {
-    return Thread.currentThread().getId() == Looper.getMainLooper().getThread().getId();
-  }
-
-  public static boolean isUndefined(float value) {
-    return Float.isNaN(value);
-  }
-
-
-  public static float getFloatByViewport(Object value, int viewport) {
-    if (value == null) {
-      return Float.NaN;
-    }
-    String temp = value.toString().trim();
-    if (Constants.Name.AUTO.equals(temp)
-            || Constants.Name.UNDEFINED.equals(temp)
-            || TextUtils.isEmpty(temp)) {
-      WXLogUtils.e("Argument Warning ! value is " + temp + "And default Value:" + Float.NaN);
-      return Float.NaN;
-    }
-
-    if (temp.endsWith("wx")) {
-      try {
-        return transferWx(temp, viewport);
-      } catch (NumberFormatException e) {
-        WXLogUtils.e("Argument format error! value is " + value, e);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    } else if (temp.endsWith("px")) {
-      try {
-        temp = temp.substring(0, temp.indexOf("px"));
-        return Float.parseFloat(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    } else {
-      try {
-        return Float.parseFloat(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }
-    return Float.NaN;
-  }
-
-  public static float getFloat(Object value) {
-    return getFloat(value, Float.NaN);
-  }
-
-  public static Float getFloat(Object value, @Nullable Float df) {
-    if (value == null) {
-      return df;
-    }
-
-    String temp = value.toString().trim();
-    if(Constants.Name.AUTO.equals(temp)
-            || Constants.Name.UNDEFINED.equals(temp)
-            || TextUtils.isEmpty(temp)){
-      WXLogUtils.e("Argument Warning ! value is " + temp + "And default Value:"+Float.NaN);
-      return df;
-    }
-    if (temp.endsWith("wx")) {
-      try {
-        return transferWx(temp, 750);
-      } catch (NumberFormatException e) {
-        WXLogUtils.e("Argument format error! value is " + value, e);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }else if (temp.endsWith("px")) {
-      try {
-        temp = temp.substring(0, temp.indexOf("px"));
-        return Float.parseFloat(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }else {
-      try {
-        return Float.parseFloat(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }
-    return df;
-  }
-
-  private static float transferWx(String stringWithWXPostfix, int viewport) {
-    if(null == stringWithWXPostfix) {
-      return 0;
-    }
-    String temp = stringWithWXPostfix;
-    if(stringWithWXPostfix.endsWith("wx")) {
-      temp = stringWithWXPostfix.substring(0, stringWithWXPostfix.indexOf("wx"));
-    }
-    Float f = Float.parseFloat(temp);
-    float density = WXEnvironment.sApplication.getResources().getDisplayMetrics().density;
-    return density * f * viewport / WXViewUtils.getScreenWidth();
-  }
-
-  public static float fastGetFloat(String raw, int precision){
-    if(!TextUtils.isEmpty(raw)){
-      boolean positive=true;
-      int loc=0;
-      if(raw.charAt(0)=='-'){
-        positive=false;
-        loc++;
-      }
-      else if(raw.charAt(0)=='+'){
-        loc++;
-      }
-
-      char digit;
-      float result=0;
-      while (loc<raw.length() && (digit=raw.charAt(loc))>='0'&&digit<='9'){
-        result=result*10+digit-'0';
-        loc++;
-      }
-
-      if(loc<raw.length()){
-        if(raw.charAt(loc)=='.'){
-          loc++;
-          int remainderLength=10;
-          int counter=0;
-          while(loc<raw.length() &&
-                  counter<precision &&
-                  ((digit=raw.charAt(loc))>='0'&& digit<='9')){
-            result+=(digit-'0')/(float)remainderLength;
-            remainderLength*=10;
-            loc++;
-            counter++;
-          }
-        }
-        else{
-          // throw new NumberFormatException("Illegal separator");
-        }
-      }
-
-      if(!positive)
-        result*=-1;
-      return result;
-    }
-    return 0;
-    // throw new NumberFormatException("NullNumber");
-  }
-
-  /**
-   * Parse string representation of float. This method intend to be faster than
-   * {@link Float#parseFloat(String)}, but less accuracy.
-   * @param raw
-   * @return
-   */
-  public static float fastGetFloat(String raw){
-    return fastGetFloat(raw, Integer.MAX_VALUE);
-  }
-
-  public static int parseInt(String value) {
-    try {
-      if (!TextUtils.isEmpty(value) && !value.contains(".")) {
-        return Integer.parseInt(value);
-      }
-    } catch (NumberFormatException e) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(WXLogUtils.getStackTrace(e));
-      }
-    }
-    return 0;
-  }
-
-  public static int parseInt(Object value) {
-    return parseInt(String.valueOf(value));
-  }
-
-  public static float parseFloat(Object value) {
-    return parseFloat(String.valueOf(value));
-  }
-
-  public static float parseFloat(String value) {
-    try {
-      if (!TextUtils.isEmpty(value) && !TextUtils.equals(value, "null")) {
-        return Float.parseFloat(value);
-      } else {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils.e("WXUtils parseFloat illegal value is " + value);
-        }
-      }
-    } catch (NumberFormatException e) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e(WXLogUtils.getStackTrace(e));
-      }
-    }
-    return 0;
-  }
-
-  public static int getInt(Object value) {
-    return getInteger(value, 0);
-  }
-
-  public static @Nullable Integer getInteger(@Nullable Object value, @Nullable Integer df) {
-
-    if (value == null) {
-      return df;
-    }
-
-    String temp = value.toString().trim();
-    String key = temp;
-    Integer cache = sCache.get(key);
-    if (cache != null) {
-      return cache;
-    } else {
-      Integer ret = df;
-      String suffix = "";
-      if (temp.length() >= 2) {
-        suffix = temp.substring(temp.length() - 2, temp.length());
-      }
-
-      if (TextUtils.equals("wx", suffix)) {
-        if (WXEnvironment.isApkDebugable()) {
-          WXLogUtils
-              .w("the value of " + value
-                  + " use wx unit, which will be not supported soon after.");
-        }
-        try {
-          ret = (int)transferWx(temp, 750);
-        } catch (NumberFormatException e) {
-          WXLogUtils.e("Argument format error! value is " + value, e);
-        } catch (Exception e) {
-          WXLogUtils.e("Argument error! value is " + value, e);
-        }
-      } else if (TextUtils.equals("px", suffix)) {
-        try {
-          temp = temp.substring(0, temp.length() - 2);
-          if (!TextUtils.isEmpty(temp) && temp.contains(".")) {
-            ret = (int)WXUtils.parseFloat(temp);
-          } else {
-            ret = Integer.parseInt(temp);
-          }
-        } catch (NumberFormatException nfe) {
-          WXLogUtils.e("Argument format error! value is " + value, nfe);
-        } catch (Exception e) {
-          WXLogUtils.e("Argument error! value is " + value, e);
-        }
-      } else {
-        try {
-          if (!TextUtils.isEmpty(temp)) {
-            if (temp.contains(".")) {
-              ret = (int)WXUtils.parseFloat(temp);
-            } else {
-              ret = Integer.parseInt(temp);
-            }
-          } else {
-            if (WXEnvironment.isApkDebugable()) {
-              WXLogUtils.e("Argument value is null, df is" + df);
-            }
-          }
-        } catch (NumberFormatException nfe) {
-          if (WXEnvironment.isApkDebugable()) {
-            WXLogUtils.w("The parameter format is not supported", nfe);
-          }
-        } catch (Exception e) {
-          WXLogUtils.e("Argument error! value is " + value, e);
-        }
-      }
-      if (ret != null && !ret.equals(df)) {
-        sCache.put(key, ret);
-      }
-      return ret;
-    }
-  }
-
-  /**
-   * Looks like no longer usage exists, Mark deprecate first.
-   * @param value
-   * @return
-   */
-  @Deprecated
-  public static long getLong(Object value) {
-    if (value == null) {
-      return 0;
-    }
-    long result = 0;
-    String temp = value.toString().trim();
-    if (temp.endsWith("wx")) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.w("the value of " + value + " use wx unit, which will be not supported soon after.");
-      }
-      try {
-        return (long)transferWx(temp, 750);
-      } catch (NumberFormatException e) {
-        WXLogUtils.e("Argument format error! value is " + value, e);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }else if (temp.endsWith("px")) {
-      try {
-        temp = temp.substring(0, temp.indexOf("px"));
-        return Long.parseLong(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }else {
-      try {
-        return Long.parseLong(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Looks like no longer usage exists, Mark deprecate first.
-   * @param value
-   * @return
-   */
-  @Deprecated
-  public static double getDouble(Object value) {
-    if (value == null) {
-      return 0;
-    }
-    double result = 0;
-    String temp = value.toString().trim();
-    if (temp.endsWith("wx")) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.w("the value of " + value + " use wx unit, which will be not supported soon after.");
-      }
-      try {
-        return transferWx(temp, 750);
-      } catch (NumberFormatException e) {
-        WXLogUtils.e("Argument format error! value is " + value, e);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }else if (temp.endsWith("px")) {
-      try {
-        temp = temp.substring(0, temp.indexOf("px"));
-        return Double.parseDouble(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }else {
-      try {
-        return Double.parseDouble(temp);
-      } catch (NumberFormatException nfe) {
-        WXLogUtils.e("Argument format error! value is " + value, nfe);
-      } catch (Exception e) {
-        WXLogUtils.e("Argument error! value is " + value, e);
-      }
-    }
-
-    return result;
-  }
-
-  @Deprecated
-  public static boolean isTabletDevice() {
-    try{
-      return (WXEnvironment.getApplication().getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
-    }catch (Exception e){
-      //
-    }
-    return false;
-  }
-
-  public static Boolean getBoolean(@Nullable Object value, @Nullable Boolean df) {
-
-    if (value == null)
-      return df;
-    if (TextUtils.equals("false",value.toString())) {
-      return false;
-    } else if (TextUtils.equals("true",value.toString())) {
-      return true;
-    }
-    return df;
-  }
-
-  public static long getAvailMemory(Context context){
-    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-    ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
-    am.getMemoryInfo(mi);
-    //mi.availMem;
-    //return Formatter.formatFileSize(context, mi.availMem);
-    WXLogUtils.w("app AvailMemory ---->>>"+mi.availMem/(1024*1024));
-    return mi.availMem/(1024*1024);
-  }
-
-  public static String getString(@Nullable Object value,@Nullable String df) {
-
-    if (value == null)
-      return df;
-
-    String originValue;
-    if (value instanceof String) {
-      originValue = (String) value;
-    } else {
-      originValue = value.toString();
-    }
-
-    return originValue;
-  }
-
-  public static int parseUnitOrPercent(String raw, int unit) {
-    int suffix;
-    if ((suffix = raw.lastIndexOf(WXUtils.PERCENT)) != -1) {
-      return parsePercent(raw.substring(0, suffix), unit);
-    }
-    else {
-      return WXUtils.parseInt(raw);
-    }
-  }
-
-  private static int parsePercent(String raw, int unit){
-    return (int)(Float.parseFloat(raw) / HUNDRED * unit);
-  }
-
-  /**
-   * Get a banner data in JSON format from a bundle content.
-   * A bundle banner looks like below:
-   * \/*!count
-   *  * {
-   *  *   version: "0.2.1.20170104-release",
-   *  *   create: "20170207171112",
-   *  *   git: "banner--772c915",
-   *  *   digest: "c709b7f91867e371b24f54d6aeea232a"
-   *  * }
-   *  !*\/
-   *
-   * @param content a bundle content
-   * @return
-   */
-  public static String getBundleBanner(String content) {
-    final String commentBegin = "/*!";
-    final String commentEnd = "!*/";
-    final String asteriskRegex = "\\*";
-    final String replacement = "";
-
-    int offsetCountBegin = content.indexOf(commentBegin);
-    if (offsetCountBegin == -1) {
-      return null;
-    }
-    offsetCountBegin += commentBegin.length();
-    int offsetCountEnd = indexLineBreak(content, offsetCountBegin);
-    if (offsetCountEnd == -1) {
-      return null;
-    }
-    String countStr = content.substring(offsetCountBegin, offsetCountEnd);
-    int count = Integer.parseInt(countStr);
-
-    String commentBody = content.substring(offsetCountEnd + 1, offsetCountEnd + 1 + count);
-    int offsetBodyEnd = commentBody.lastIndexOf(commentEnd);
-    if (offsetBodyEnd == -1) {
-      return null;
-    }
-    commentBody = commentBody.substring(0, offsetBodyEnd);
-
-    StringBuilder commentBodyBuilder = new StringBuilder();
-    String[] items = splitLineBreak(commentBody);
-
-    for (String item : items) {
-      commentBodyBuilder.append(item.replaceFirst(asteriskRegex, replacement));
-    }
-
-    return commentBodyBuilder.toString();
-  }
-
-  private static int indexLineBreak(String str, int fromIndex) {
-    final String lineBreakIos = "\r";
-    final String lineBreakUnix = "\n";
-    final String linebreakWin = "\r\n";
-
-    int index = str.indexOf(lineBreakIos, fromIndex);
-    if (index == -1) {
-      index = str.indexOf(lineBreakUnix, fromIndex);
-    }
-    if (index == -1) {
-      index = str.indexOf(linebreakWin, fromIndex);
-    }
-
-    return index;
-  }
-
-  private static String[] splitLineBreak(String str) {
-    final String lineBreakIos = "\r";
-    final String lineBreakUnix = "\n";
-    final String linebreakWin = "\r\n";
-    String[] items = str.split(lineBreakIos);
-
-    if (items.length == 1) {
-      items = str.split(lineBreakUnix);
-    }
-    if (items.length == 1) {
-      items = str.split(linebreakWin);
-    }
-
-    return items;
-  }
-
-
-  
-  /**
-   * get number
-   * */
-  public static int getNumberInt(Object value, int defaultValue){
-    if(value == null){
-      return  defaultValue;
-    }
-    if(value instanceof  Number){
-      return  ((Number) value).intValue();
-    }
-    try{
-      String number = value.toString();
-      if(number.indexOf('.') >= 0) {
-        return (int) Float.parseFloat(value.toString());
-      }else{
-        return  Integer.parseInt(number);
-      }
-    }catch (Exception e){return  defaultValue;}
-  }
-
-  public static boolean checkGreyConfig(String group,String key,String defaultValue){
-      IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
-      if (null == configAdapter) {
-        return false;
-      }
-      double randomValue = Math.random() * 100;
-      double max = 100;
-      try {
-        String configValue = configAdapter.getConfig(group, key, defaultValue);
-        max = Double.valueOf(configValue);
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-      return randomValue < max;
-  }
-
-  private static final long sInterval = System.currentTimeMillis() - SystemClock.uptimeMillis();
-
-  public static long getFixUnixTime(){
-    return  sInterval + SystemClock.uptimeMillis();
-  }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewToImageUtil.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewToImageUtil.java
deleted file mode 100755
index b486fb5..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewToImageUtil.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.MediaStore;
-import android.support.annotation.ColorInt;
-import android.view.View;
-
-import com.taobao.weex.WXSDKManager;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Created by miomin on 7/25/17.
- */
-public class WXViewToImageUtil {
-
-    public static int mBackgroundColor = Color.TRANSPARENT;
-
-    /**
-     * Generate image and return path via callback
-     */
-    public static void generateImage(final View imageView, final int width,
-                                     @ColorInt final int backgroundColor, final OnImageSavedCallback mOnImageSavedCallback) {
-
-        mBackgroundColor = backgroundColor;
-
-        // Only one save image task occurs at the same time
-        WXSDKManager.getInstance().getWXWorkThreadManager().post(new Thread(new Runnable() {
-            @Override
-            public void run() {
-                // Generate bitmap from ImageView
-                Bitmap bitmap = getBitmapFromImageView(imageView, width);
-
-                if (bitmap == null) {
-                    if (mOnImageSavedCallback != null) {
-                        mOnImageSavedCallback.onSaveFailed("Image is empty");
-                    }
-                    return;
-                }
-
-                // Sava bitmap to gallery
-                final String destPath = saveBitmapToGallery(imageView.getContext(), bitmap, mOnImageSavedCallback);
-
-                new Handler(Looper.getMainLooper()).post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (mOnImageSavedCallback != null) {
-                            mOnImageSavedCallback.onSaveSucceed(destPath);
-                            imageView.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(destPath)));
-                        }
-                    }
-                });
-            }
-        }));
-    }
-
-    /**
-     * Save bitmap to gallery
-     * @return image save path
-     */
-    public static String saveBitmapToGallery(Context context, Bitmap bitmap, final OnImageSavedCallback mOnImageSavedCallback) {
-
-        // Save image
-        File appDir = new File(Environment.getExternalStorageDirectory(), "Weex");
-        if (!appDir.exists()) {
-            appDir.mkdir();
-        }
-
-        String fileName = System.currentTimeMillis() + ".jpg";
-        File file = new File(appDir, fileName);
-
-        try {
-            FileOutputStream fos = new FileOutputStream(file);
-            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
-            fos.flush();
-            fos.close();
-        } catch (FileNotFoundException e) {
-            if (mOnImageSavedCallback != null)
-                mOnImageSavedCallback.onSaveFailed("Image creation failed due to system reason");
-            e.printStackTrace();
-        } catch (IOException e) {
-            if (mOnImageSavedCallback != null)
-                mOnImageSavedCallback.onSaveFailed("Android IOException");
-            e.printStackTrace();
-        }
-
-        // Insert the image file into the system gallery
-        try {
-            MediaStore.Images.Media.insertImage(context.getContentResolver(),
-                    file.getAbsolutePath(), fileName, null);
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
-        }
-
-        // Notify the system gallery update
-        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + appDir.getAbsolutePath() + "/" + fileName)));
-
-        return file.getAbsolutePath();
-    }
-
-    /**
-     * Save state callback
-     */
-    public interface OnImageSavedCallback {
-        void onSaveSucceed(String path);
-        void onSaveFailed(String errorDesc);
-    }
-
-    /**
-     * Get bitmap from imageview
-     */
-    public static Bitmap getBitmapFromImageView(final View view, int width) {
-        if (view.getWidth() <= 0 || view.getHeight() <= 0) {
-            view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
-                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
-            view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
-        }
-
-        view.setDrawingCacheEnabled(true);
-        Bitmap bitmap = view.getDrawingCache();
-        return bitmap;
-    }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java
deleted file mode 100644
index e6c0ee7..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.RectF;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Build;
-import android.os.Build.VERSION_CODES;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.WindowManager;
-
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRuntimeException;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.flat.widget.Widget;
-import com.taobao.weex.ui.flat.widget.WidgetGroup;
-import com.taobao.weex.ui.view.border.BorderDrawable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Utility class for views
- */
-public class WXViewUtils {
-
-  @IntDef({PixelFormat.TRANSLUCENT, PixelFormat.TRANSPARENT, PixelFormat.OPAQUE})
-  @Retention(RetentionPolicy.SOURCE)
-  public @interface Opacity {}
-
-  /**
-   * Use {@link PixelFormat#TRANSLUCENT} instead
-   */
-  @Deprecated
-  public static final int TRANSLUCENT = PixelFormat.TRANSLUCENT;
-
-  /**
-   * Use {@link PixelFormat#TRANSPARENT} instead.
-   */
-  @Deprecated
-  public static final int TRANSPARENT = PixelFormat.TRANSPARENT;
-
-  /**
-   * Use {@link PixelFormat#OPAQUE} instead
-   */
-  @Deprecated
-  public static final int OPAQUE = PixelFormat.OPAQUE;
-
-  public static final int DIMENSION_UNSET = -1;
-  private static final boolean mUseWebPx = false;
-
-  private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
-
-  @SuppressLint("NewApi")
-  public static int generateViewId() {
-
-    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
-      for (;;) {
-        final int result = sNextGeneratedId.get();
-        // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
-        int newValue = result + 1;
-        if (newValue > 0x00FFFFFF)
-          newValue = 1; // Roll over to 1, not 0.
-        if (sNextGeneratedId.compareAndSet(result, newValue)) {
-          return result;
-        }
-      }
-    } else {
-      return View.generateViewId();
-    }
-  }
-
-  private static int mScreenWidth;
-  private static int mScreenHeight;
-
-
-  public static int getWeexHeight(String instanceId){
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance != null) {
-      int weexHeight = instance.getWeexHeight();
-      if (weexHeight >= 0 || weexHeight == -2) {
-        return weexHeight;
-      }
-      else {
-        return getScreenHeight(WXEnvironment.sApplication);
-      }
-    }
-    return -3;
-  }
-
-
-
-  public static int getWeexWidth(String instanceId){
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    if (instance != null) {
-      int weexWidth = instance.getWeexWidth();
-      if (weexWidth >= 0 || weexWidth == -2) {
-        return weexWidth;
-      }
-      else {
-        return getScreenWidth(WXEnvironment.sApplication);
-      }
-    }
-    return -3;
-  }
-
-  @Deprecated
-  public static int getScreenWidth( ) {
-    return getScreenWidth(WXEnvironment.sApplication);
-  }
-
-  @Deprecated
-  public static int setScreenWidth(int screenWidth) {
-    return mScreenWidth = screenWidth;
-  }
-
-  public static float getScreenDensity(Context ctx){
-    if(ctx != null){
-      try{
-        Resources res = ctx.getResources();
-        return res.getDisplayMetrics().density;
-      }catch (Exception e){
-        WXLogUtils.e("getScreenDensityDpi exception:"+e.getMessage());
-      }
-    }
-    return Constants.Value.DENSITY;
-  }
-
-  public static void updateApplicationScreen(Context context){
-    if(context == null || WXEnvironment.sApplication == null){
-        return;
-    }
-    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
-    DisplayMetrics displayMetrics = WXEnvironment.sApplication.getResources().getDisplayMetrics();
-    displayMetrics.heightPixels = metrics.heightPixels;
-    displayMetrics.widthPixels = metrics.widthPixels;
-    displayMetrics.density = metrics.density;
-    displayMetrics.densityDpi = metrics.densityDpi;
-    displayMetrics.scaledDensity = metrics.scaledDensity;
-    displayMetrics.xdpi = metrics.xdpi;
-  }
-
-  public static int getScreenWidth(Context ctx) {
-    if(ctx!=null){
-      Resources res = ctx.getResources();
-      mScreenWidth = res.getDisplayMetrics().widthPixels;
-      if(WXEnvironment.SETTING_FORCE_VERTICAL_SCREEN){
-        mScreenHeight = res
-                .getDisplayMetrics()
-                .heightPixels;
-        mScreenWidth = mScreenHeight > mScreenWidth ? mScreenWidth : mScreenHeight;
-      }
-    } else if(WXEnvironment.isApkDebugable()){
-      throw new WXRuntimeException("Error Context is null When getScreenHeight");
-    }
-    return mScreenWidth;
-  }
-
-
-  public static int getStatusBarHeight(Context context){
-      Resources resources = context.getResources();
-      int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
-      if (resourceId > 0) {
-        int statusBarHeight = resources.getDimensionPixelSize(resourceId);
-        return statusBarHeight;
-      }
-      return -1;
-  }
-
-
-  @Deprecated
-  public static int getScreenHeight() {
-    return getScreenHeight(WXEnvironment.sApplication);
-  }
-
-
-  public static int getScreenHeight(String instanceId){
-    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
-    return instance.isFullScreenHeightEnabled()?getFullScreenHeight(WXEnvironment.sApplication):getScreenHeight(WXEnvironment.sApplication);
-  }
-
-//get screen height with status bar on full screen
-  public static int getFullScreenHeight(Context cxt) {
-    if(cxt!=null){
-      WindowManager wm;
-      Resources res = cxt.getResources();
-      if(Build.VERSION.SDK_INT >= 17 && (wm = (WindowManager)cxt.getSystemService(Context.WINDOW_SERVICE)) != null
-              && wm.getDefaultDisplay() != null){
-        Point size = new Point();
-        wm.getDefaultDisplay().getRealSize(size);
-        mScreenHeight = size.y;
-      }
-      else {
-        mScreenHeight = cxt.getResources().getDisplayMetrics().heightPixels;
-      }
-      if(WXEnvironment.SETTING_FORCE_VERTICAL_SCREEN){
-        mScreenWidth = res
-                .getDisplayMetrics()
-                .widthPixels;
-        mScreenHeight = mScreenHeight > mScreenWidth ? mScreenHeight : mScreenWidth;
-      }
-    } else if (WXEnvironment.isApkDebugable()){
-      throw new WXRuntimeException("Error Context is null When getScreenHeight");
-    }
-    return mScreenHeight;
-  }
-//  get screen height without status bar
-  public static int getScreenHeight(Context cxt) {
-    if(cxt!=null){
-      Resources res = cxt.getResources();
-      mScreenHeight = res.getDisplayMetrics().heightPixels;
-      if(WXEnvironment.SETTING_FORCE_VERTICAL_SCREEN){
-        mScreenWidth = res
-                .getDisplayMetrics()
-                .widthPixels;
-        mScreenHeight = mScreenHeight > mScreenWidth ? mScreenHeight : mScreenWidth;
-      }
-    } else if (WXEnvironment.isApkDebugable()){
-      throw new WXRuntimeException("Error Context is null When getScreenHeight");
-    }
-    return mScreenHeight;
-  }
-
-
-  /**
-   * Convert distance from JS,CSS to native. As the JS considers the width of the screen is 750px.
-   * There must be a transform when accessing distance from JS,CSS and use it.
-   * Basically, this method calculates a scale factor(ScreenWidth/750) and use apply this scale
-   * factor to JS,CSS distance.
-   * @param pxValue the raw distance from JS or CSS. The result will be rounded to a closet int.
-   * @return the actual distance in the screen.
-   */
-
-  @Deprecated
-  public static float getRealPxByWidth(float pxValue) {
-    return getRealPxByWidth(pxValue,750);
-  }
-  public static float getRealPxByWidth(float pxValue,int customViewport) {
-    if (Float.isNaN(pxValue)) {
-      return pxValue;
-    }
-    if (mUseWebPx) {
-      return (float) Math.rint(pxValue);
-    } else {
-      float realPx = (pxValue * getScreenWidth() / customViewport);
-      return realPx > 0.005 && realPx < 1 ? 1 : (float) Math.rint(realPx);
-    }
-  }
-
-  @Deprecated
-  public static float getRealSubPxByWidth(float pxValue) {
-    return getRealSubPxByWidth(pxValue,750);
-  }
-
-  public static float getRealSubPxByWidth(float pxValue,int customViewport) {
-    if (Float.isNaN(pxValue)) {
-      return pxValue;
-    }
-    if (mUseWebPx) {
-      return (float) Math.rint(pxValue);
-    } else {
-      float realPx = (pxValue * getScreenWidth() / customViewport);
-      return realPx > 0.005 && realPx < 1 ? 1 : realPx;
-    }
-  }
-
-  /**
-   *  Internal interface that just for debug, you should never call this method because of accuracy loss obviously
-   */
-  @Deprecated
-  public static float getWeexPxByReal(float pxValue) {
-    return getWeexPxByReal(pxValue,750);
-  }
-
-  public static float getWeexPxByReal(float pxValue,int customViewport) {
-    if (Float.isNaN(pxValue)) {
-      return pxValue;
-    }
-    if (mUseWebPx) {
-      return (float) Math.rint(pxValue);
-    } else {
-      return pxValue * customViewport / getScreenWidth();
-    }
-  }
-
-  @Deprecated
-  public static float getRealPxByWidth2(float pxValue) {
-    return getRealPxByWidth2(pxValue,750);
-  }
-  public static int getRealPxByWidth2(float pxValue,int customViewport) {
-    if (mUseWebPx) {
-      return (int) pxValue;
-    } else {
-      float realPx = (pxValue * getScreenWidth() / customViewport);
-      return realPx > 0.005 && realPx < 1 ? 1 : (int) realPx - 1;
-    }
-  }
-
-  /**
-   * Convert distance from native to JS,CSS. As the JS considers the width of the screen is 750px.
-   * There must be a transform when return distance to JS,CSS.
-   * Basically, this method calculates a scale factor(ScreenWidth/750) and use apply this scale
-   * factor to native distance.
-   * @param pxValue the raw distance of native. The result will be rounded to a closet int.
-   * @return the distance in JS,CSS where the screenWidth is 750 px.
-   */
-  @Deprecated
-  public static float getWebPxByWidth(float pxValue) {
-    return getWebPxByWidth(pxValue,750);
-  }
-
-  public static float getWebPxByWidth(float pxValue,int customViewport) {
-    if (pxValue < -1.9999 && pxValue > -2.005) {
-      return Float.NaN;
-    }
-    if (mUseWebPx) {
-      return pxValue;
-    } else {
-      float realPx = (pxValue * customViewport / getScreenWidth());
-      return realPx > 0.005 && realPx < 1 ? 1 : realPx;
-    }
-  }
-
-
-  /**
-   * Convert dp to px
-   * @param dpValue the dp value to be converted
-   * @return the px value
-   */
-  public static int dip2px(float dpValue) {
-    float scale = 2;
-    try {
-      scale = WXEnvironment.getApplication().getResources()
-              .getDisplayMetrics().density;
-    } catch (Exception e) {
-      WXLogUtils.e("[WXViewUtils] dip2px:", e);
-    }
-    float finalPx = (dpValue * scale + 0.5f);
-    return finalPx > 0 && finalPx < 1 ? 1 : (int) finalPx;
-  }
-
-  public static boolean onScreenArea(View view) {
-    if (view == null || view.getVisibility() != View.VISIBLE) {
-      return false;
-    }
-
-    int[] p = new int[2];
-    view.getLocationOnScreen(p);
-    LayoutParams lp = view.getLayoutParams();
-    int viewH = 0;
-    if (lp != null) {
-      viewH = lp.height;
-    } else {
-      viewH = view.getHeight();
-    }
-
-    return (p[1] > 0 && (p[1] - WXViewUtils.getScreenHeight(WXEnvironment.sApplication) < 0))
-            || (viewH + p[1] > 0 && p[1] <= 0);
-  }
-
-  /**
-   * Multiplies the color with the given alpha.
-   *
-   * @param color color to be multiplied
-   * @param alpha value between 0 and 255
-   * @return multiplied color
-   */
-  public static int multiplyColorAlpha(int color, int alpha) {
-    if (alpha == 255) {
-      return color;
-    }
-    if (alpha == 0) {
-      return color & 0x00FFFFFF;
-    }
-    alpha = alpha + (alpha >> 7); // make it 0..256
-    int colorAlpha = color >>> 24;
-    int multipliedAlpha = colorAlpha * alpha >> 8;
-    return (multipliedAlpha << 24) | (color & 0x00FFFFFF);
-  }
-
-  @Opacity
-  public static int getOpacityFromColor(int color) {
-    int colorAlpha = color >>> 24;
-    if (colorAlpha == 255) {
-      return PixelFormat.OPAQUE;
-    } else if (colorAlpha == 0) {
-      return PixelFormat.TRANSPARENT;
-    } else {
-      return PixelFormat.TRANSLUCENT;
-    }
-  }
-
-  @SuppressWarnings("deprecation")
-  public static void setBackGround(View view, Drawable drawable, WXComponent component) {
-    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN){
-      view.setBackgroundDrawable(drawable);
-    }
-    else{
-      try {
-        view.setBackground(drawable);
-      } catch (Exception e) {
-        if (component == null)
-          return;
-        WXExceptionUtils.commitCriticalExceptionRT(component.getInstanceId(),
-                WXErrorCode.WX_RENDER_ERR_TEXTURE_SETBACKGROUND,
-                component.getComponentType() + " setBackGround for android view",
-                WXErrorCode.WX_RENDER_ERR_TEXTURE_SETBACKGROUND.getErrorMsg() + ": TextureView doesn't support displaying a background drawable!",
-                null);
-      }
-    }
-  }
-
-  public static @Nullable
-  BorderDrawable getBorderDrawable(@NonNull View view){
-    Drawable drawable=view.getBackground();
-    if(drawable instanceof BorderDrawable){
-      return (BorderDrawable) drawable;
-    }
-    else if(drawable instanceof LayerDrawable){
-      if(((LayerDrawable) drawable).getNumberOfLayers()>1) {
-        Drawable innerDrawable=((LayerDrawable) drawable).getDrawable(0);
-        if(innerDrawable instanceof BorderDrawable){
-          return (BorderDrawable) innerDrawable;
-        }
-      }
-    }
-    return null;
-  }
-
-  public static void clipCanvasWithinBorderBox(View targetView, Canvas canvas) {
-    Drawable drawable;
-    if (clipCanvasDueToAndroidVersion(canvas) &&
-            clipCanvasIfAnimationExist(targetView) &&
-            ((drawable = targetView.getBackground()) instanceof BorderDrawable)) {
-      BorderDrawable borderDrawable = (BorderDrawable) drawable;
-      if (borderDrawable.isRounded()) {
-        if (clipCanvasIfBackgroundImageExist(targetView, borderDrawable)) {
-          Path path = borderDrawable.getContentPath(
-                  new RectF(0, 0, targetView.getWidth(), targetView.getHeight()));
-          canvas.clipPath(path);
-        }
-      }
-    }
-  }
-
-  public static void clipCanvasWithinBorderBox(Widget widget, Canvas canvas) {
-    BorderDrawable borderDrawable;
-    if (clipCanvasDueToAndroidVersion(canvas) &&
-            clipCanvasIfAnimationExist(null) &&
-            (borderDrawable=widget.getBackgroundAndBorder())!=null ) {
-      if (borderDrawable.isRounded() && clipCanvasIfBackgroundImageExist(widget, borderDrawable)) {
-        Path path = borderDrawable.getContentPath(
-                new RectF(0, 0, widget.getBorderBox().width(), widget.getBorderBox().height()));
-        canvas.clipPath(path);
-      }
-      else {
-        canvas.clipRect(widget.getBorderBox());
-      }
-    }
-  }
-
-  /**
-   * According to https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported
-   API 18 or higher supports clipPath to canvas based on hardware acceleration.
-   * @param canvas
-   * @return
-   */
-  private static boolean clipCanvasDueToAndroidVersion(Canvas canvas) {
-    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 ||
-            !canvas.isHardwareAccelerated();
-  }
-
-  /**
-   * According to https://code.google.com/p/android/issues/detail?id=225556&sort=-id&colspec=ID
-   * clipPath doesn't work with rotation nor scale when API level is 24.
-   * As animation will not cause redraw if hardware-acceleration enabled, clipCanvas feature has
-   * to be disabled when API level is 24 without considering the animation property.
-   */
-  private static boolean clipCanvasIfAnimationExist(View targetView) {
-    if (Build.VERSION.SDK_INT != VERSION_CODES.N) {
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  /**
-   * Due limitation in Android platform, the linear gradient in the following page will not be
-   * rounded if {@link Canvas#clipPath(Path)} of the parent view invoked when API level is lower
-   * than 21.
-   * http://dotwe.org/weex/963c9ade129f86757cecdd85651cd30e
-   * @param targetView
-   * @param borderDrawable
-   * @return
-   */
-  private static boolean clipCanvasIfBackgroundImageExist(@NonNull View targetView,
-                                                          @NonNull BorderDrawable borderDrawable) {
-    if (targetView instanceof ViewGroup) {
-      View child;
-      ViewGroup parent = ((ViewGroup) targetView);
-      int count = parent.getChildCount();
-      for (int i = 0; i < count; i++) {
-        child = parent.getChildAt(i);
-        if (child.getBackground() instanceof BorderDrawable &&
-                ((BorderDrawable) child.getBackground()).hasImage() &&
-                Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  private static boolean clipCanvasIfBackgroundImageExist(@NonNull Widget widget,
-                                                          @NonNull BorderDrawable borderDrawable) {
-    if (widget instanceof WidgetGroup) {
-      for (Widget child : ((WidgetGroup) widget).getChildren()) {
-        if (child.getBackgroundAndBorder().hasImage() &&
-                Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  public static boolean isViewVisible(View v) {
-    if (null == v){
-      return false;
-    }
-
-    boolean isAttachToWindow = Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT
-        ?v.isAttachedToWindow()
-        :v.getWindowToken() != null;
-
-    if (!isAttachToWindow){
-      return false;
-    }
-    if (v.getVisibility() != View.VISIBLE || v.getAlpha()<=0){
-      return false;
-    }
-
-    Drawable bacDrawable = v.getBackground();
-    if (null == bacDrawable){
-      return true;
-    }
-    if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT){
-      return bacDrawable.getAlpha()>0;
-    }
-    //< 4.4
-    if (bacDrawable instanceof ColorDrawable){
-      int alpha = Color.alpha(((ColorDrawable) bacDrawable).getColor());
-      return alpha >0;
-    }else if (bacDrawable instanceof BitmapDrawable){
-      Paint paint = ((BitmapDrawable) bacDrawable).getPaint();
-      return paint.getAlpha() > 0;
-    }
-    return true;
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXWsonJSONSwitch.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXWsonJSONSwitch.java
deleted file mode 100644
index 0271bdf..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXWsonJSONSwitch.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.support.annotation.NonNull;
-
-import com.alibaba.fastjson.JSON;
-import com.taobao.weex.bridge.WXJSObject;
-import com.taobao.weex.wson.Wson;
-import com.taobao.weex.wson.WsonUtils;
-
-/**
- * Created by furture on 2018/5/17.
- */
-
-public class WXWsonJSONSwitch {
-
-    private static final String TAG = "WXSwitch";
-
-    /**
-     * switch input data to target according to config, if not use wson return normal data
-     * */
-    public static  final byte[] convertJSONToWsonIfUseWson(byte[] json){
-        if(!USE_WSON){
-            return json;
-        }
-        if(json == null){
-            return null;
-        }
-        String str = new String(json);
-        if(str.startsWith("[")){
-            return WsonUtils.toWson(JSON.parseArray(str));
-        }
-        return WsonUtils.toWson(JSON.parse(str));
-    }
-
-    /**
-     * parse json or wson data by config switch
-     * */
-    public static final Object parseWsonOrJSON(byte[] data){
-        if(data == null){
-            return  null;
-        }
-        try{
-            if(USE_WSON){
-                return  Wson.parse(data);
-            }else{
-                return  JSON.parse(new String(data, "UTF-8"));
-            }
-        }catch (Exception e){
-            WXLogUtils.e(TAG, e);
-            if(USE_WSON){  //fallback
-                return  JSON.parse(new String(data));
-            }else{
-                return Wson.parse(data);
-            }
-        }
-    }
-
-    /**
-     * to wson or wson WXJSObject
-     * */
-    public static final WXJSObject toWsonOrJsonWXJSObject(Object tasks){
-        if(tasks == null){
-            return new WXJSObject(null);
-        }
-        if(tasks.getClass() == WXJSObject.class){
-            return (WXJSObject) tasks;
-        }
-        if(USE_WSON) {
-            return new WXJSObject(WXJSObject.WSON, Wson.toWson(tasks));
-        }else{
-            return new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(tasks));
-        }
-    }
-
-
-    public static  final Object convertWXJSObjectDataToJSON(WXJSObject object){
-        if(object.type == WXJSObject.WSON){
-            return JSON.parse(Wson.parse((byte[]) object.data).toString());
-        }else{
-            return JSON.parse(object.data.toString());
-        }
-    }
-
-
-
-    /**
-     * config whether use json or wson,  you should update this value by updateGlobalConfig(String config)
-     * in WXBridgeManager class  method
-     * */
-    public static  boolean USE_WSON = true;
-
-
-    /**wson off */
-    public static final String WSON_OFF = "wson_off";
-
-
-    public @NonNull
-    static String fromObjectToJSONString(WXJSObject obj) {
-        if(obj != null && obj.type == WXJSObject.WSON){
-            Object data = Wson.parse((byte[]) obj.data);
-            if(data != null){
-                return  data.toString();
-            }
-        }
-        return WXJsonUtils.fromObjectToJSONString(obj,false);
-    }
-
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/batch/BactchExecutor.java b/android/sdk/src/main/java/com/taobao/weex/utils/batch/BactchExecutor.java
deleted file mode 100644
index 60ac7f4..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/batch/BactchExecutor.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.batch;
-
-/**
- * Created by sospartan on 8/24/16.
- */
-public interface BactchExecutor {
-  void post(Runnable runnable);
-
-  void setInterceptor(Interceptor interceptor);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/batch/BatchOperationHelper.java b/android/sdk/src/main/java/com/taobao/weex/utils/batch/BatchOperationHelper.java
deleted file mode 100644
index 3c79d53..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/batch/BatchOperationHelper.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.batch;
-
-import com.taobao.weex.utils.batch.BactchExecutor;
-import com.taobao.weex.utils.batch.Interceptor;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Created by sospartan on 8/24/16.
- */
-public class BatchOperationHelper implements Interceptor {
-
-
-  private BactchExecutor mExecutor;
-  private CopyOnWriteArrayList<Runnable> sRegisterTasks = new CopyOnWriteArrayList<>();
-  private boolean isCollecting = false;
-
-  public BatchOperationHelper(BactchExecutor executor){
-    mExecutor = executor;
-    executor.setInterceptor(this);
-    isCollecting = true;
-  }
-
-  @Override
-  public boolean take(Runnable runnable) {
-    if(isCollecting){
-      sRegisterTasks.add(runnable);
-      return true;
-    }
-    return false;
-  }
-
-  /**
-   * Post all tasks to executor. Can only be called once.
-   */
-  public void flush(){
-    isCollecting = false;
-    mExecutor.post(new Runnable() {
-      @Override
-      public void run() {
-        Iterator<Runnable> iterator = sRegisterTasks.iterator();
-        while(iterator.hasNext()){
-          Runnable item = iterator.next();
-          item.run();
-//          iterator.remove();
-          sRegisterTasks.remove(item);
-        }
-      }
-    });
-    mExecutor.setInterceptor(null);
-  }
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/batch/Interceptor.java b/android/sdk/src/main/java/com/taobao/weex/utils/batch/Interceptor.java
deleted file mode 100644
index 80194ec..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/batch/Interceptor.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.batch;
-
-/**
- * Created by sospartan on 8/24/16.
- */
-public interface Interceptor {
-  boolean take(Runnable runnable);
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/cache/RegisterCache.java b/android/sdk/src/main/java/com/taobao/weex/utils/cache/RegisterCache.java
deleted file mode 100644
index 69f18f3..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/cache/RegisterCache.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.cache;
-
-import com.taobao.weex.bridge.ModuleFactory;
-import com.taobao.weex.bridge.WXModuleManager;
-import com.taobao.weex.ui.IFComponentHolder;
-import com.taobao.weex.ui.WXComponentRegistry;
-import com.taobao.weex.ui.config.AutoScanConfigRegister;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-public class RegisterCache {
-    private static Map<String, ModuleCache> moduleCacheMap = new ConcurrentHashMap<>();
-    private static Map<String, ComponentCache> componentCacheMap = new ConcurrentHashMap<>();
-    private static RegisterCache registerCache;
-
-    private boolean enable = false;
-
-    private boolean enableAutoScan = true;
-
-    public static RegisterCache getInstance() {
-        if (registerCache == null) {
-            synchronized (RegisterCache.class) {
-                if (registerCache == null) {
-                    registerCache = new RegisterCache();
-                }
-            }
-        }
-        return registerCache;
-    }
-
-    private RegisterCache() {
-
-    }
-
-    private volatile boolean finished = false;
-
-    private volatile int doNotCacheSize = Integer.MAX_VALUE;
-
-    public void setEnable(boolean enable) {
-        this.enable = enable;
-    }
-
-    private boolean enableCache() {
-        return enable;
-    }
-
-    private boolean canCache() {
-        return enableCache()
-                && !finished
-                && getDoNotCacheSize() < 1;
-    }
-
-    public boolean enableAutoScan() {
-        return enableAutoScan;
-    }
-
-    public void setEnableAutoScan(boolean enableAutoScan) {
-        if(this.enableAutoScan != enableAutoScan) {
-            if(enableAutoScan) {
-                AutoScanConfigRegister.doScanConfig();
-            }
-            this.enableAutoScan = enableAutoScan;
-        }
-
-    }
-
-    private int getDoNotCacheSize() {
-        return doNotCacheSize--;
-    }
-
-    public void setDoNotCacheSize(int doNotCacheSize) {
-        this.doNotCacheSize = doNotCacheSize;
-    }
-
-    public boolean idle(boolean atCreateInstance) {
-        if (finished)
-            return true;
-
-        String message;
-        if(atCreateInstance) {
-            message = "idle from create instance";
-        } else {
-            message = "idle from external";
-        }
-
-        WXLogUtils.e(message + " cache size is " + (moduleCacheMap.size() + componentCacheMap.size()));
-
-        finished = true;
-        CacheComponentRegister();
-        CacheModuleRegister();
-        return true;
-    }
-
-    public boolean cacheModule(final String moduleName, final ModuleFactory factory, final boolean global) {
-        if (!canCache()) {
-            return false;
-        }
-        try {
-            moduleCacheMap.put(moduleName, new ModuleCache(moduleName, factory, global));
-        } catch (Exception e) {
-            return false;
-        }
-        return true;
-    }
-
-
-    public boolean cacheComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) {
-        if (!canCache()) {
-            return false;
-        }
-        try {
-            componentCacheMap.put(type, new ComponentCache(type, holder, componentInfo));
-        } catch (Exception e) {
-            return false;
-        }
-        return true;
-    }
-
-
-    private void CacheComponentRegister() {
-        if (componentCacheMap.isEmpty())
-            return;
-        WXComponentRegistry.registerComponent(componentCacheMap);
-    }
-
-
-    private void CacheModuleRegister() {
-        if (moduleCacheMap.isEmpty())
-            return;
-
-        WXModuleManager.registerModule(moduleCacheMap);
-    }
-
-    public class ModuleCache {
-        public final String name;
-        public final ModuleFactory factory;
-        public final boolean global;
-
-        ModuleCache(String moduleName, ModuleFactory factory, boolean global) {
-            this.name = moduleName;
-            this.factory = factory;
-            this.global = global;
-        }
-    }
-
-
-    public class ComponentCache {
-        public final String type;
-        public final IFComponentHolder holder;
-        public final Map<String, Object> componentInfo;
-
-        ComponentCache(String type, IFComponentHolder holder, Map<String, Object> componentInfo) {
-            this.type = type;
-            this.componentInfo = componentInfo;
-            this.holder = holder;
-        }
-    }
-
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/tools/Info.java b/android/sdk/src/main/java/com/taobao/weex/utils/tools/Info.java
deleted file mode 100644
index a9dd401..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/tools/Info.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.tools;
-
-import com.alibaba.fastjson.annotation.JSONField;
-
-public class Info{
-
-	public Info() {
-		taskInfo = new TaskInfo();
-	}
-
-	@JSONField(name="instanceId")
-	public String instanceId;
-
-	@JSONField(name="taskName")
-	public String taskName;
-
-	@JSONField(name="taskInfo")
-	public TaskInfo taskInfo;
-
-	@JSONField(name="platform")
-	public String platform;
-
-	@JSONField(name="taskId")
-	public int taskId;
-
-	@Override
- 	public String toString(){
-		return 
-			"Info : {" +
-			"instanceId = '" + instanceId + '\'' + 
-			",taskName = '" + taskName + '\'' + 
-			",taskInfo = '" + taskInfo + '\'' + 
-			",platform = '" + platform + '\'' + 
-			",taskId = '" + taskId + '\'' + 
-			"}";
-		}
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/tools/LogDetail.java b/android/sdk/src/main/java/com/taobao/weex/utils/tools/LogDetail.java
deleted file mode 100644
index c257296..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/tools/LogDetail.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.tools;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.alibaba.fastjson.annotation.JSONField;
-import com.taobao.weex.WXEnvironment;
-import java.util.Locale;
-
-public class LogDetail {
-    public static final String KeyWrod_Init = "Weex_Init";
-    public static final String KeyWords_Render = "Weex_Render";
-
-    public LogDetail() {
-        time = new Time();
-        info = new Info();
-    }
-
-    @JSONField(name = "time")
-    public Time time;
-
-    @JSONField(name = "Info")
-    public Info info;
-
-    @Override
-    public String toString() {
-        return
-                "taskName : " + info.taskName + " - LogDetail : {" +
-                        "time = '" + time + '\'' +
-                        ", info = '" + info + '\'' +
-                        "}";
-    }
-
-
-    public String keyWords = KeyWords_Render;
-
-    public void println() {
-        if(WXEnvironment.isPerf())
-        Log.e(TimeCalculator.TIMELINE_TAG," timeline " + this.keyWords + " java LogDetail: " + this.toString());
-    }
-
-    public void name(String name) {
-        time.constructor();
-        info.taskName = name;
-        if(!TextUtils.isEmpty(name)) {
-            String s = name.toLowerCase(Locale.ROOT);
-            if(s.contains("module")
-            || s.contains("component")
-                    || s.contains("framework")) {
-                this.keyWords = KeyWrod_Init;
-            }
-        }
-    }
-
-    public void keyWorkds(String keyWords) {
-        this.keyWords = keyWords;
-    }
-
-    public void taskStart() {
-        time.taskStart();
-    }
-
-    public void taskEnd() {
-        time.taskEnd();
-        println();
-    }
-
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/tools/LogSwitch.java b/android/sdk/src/main/java/com/taobao/weex/utils/tools/LogSwitch.java
deleted file mode 100644
index 8dc4c4a..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/tools/LogSwitch.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.tools;
-
-public class LogSwitch {
-
-    private int low_level = 4;
-    private int medium_level = 2;
-    private int high_level = 1;
-    private int log_switch = 0;
-    private boolean showLowLevelLog = false;
-    private boolean showMediumLevelLog = false;
-    private boolean showHighLevelLog = true;
-
-
-    public void setLog_switch() {
-        // Todo
-        // read prop
-
-        if (showLowLevelLog)
-            log_switch |= low_level;
-
-        if (showMediumLevelLog) {
-            log_switch |= medium_level;
-        }
-
-        if (showHighLevelLog) {
-            log_switch |= high_level;
-        }
-    }
-
-
-    public int getLog_switch() {
-        return log_switch;
-    }
-
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/tools/TaskInfo.java b/android/sdk/src/main/java/com/taobao/weex/utils/tools/TaskInfo.java
deleted file mode 100644
index 67bae84..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/tools/TaskInfo.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.tools;
-
-import com.alibaba.fastjson.annotation.JSONField;
-
-public class TaskInfo{
-
-	@JSONField(name="args")
-	public String args;
-
-	@JSONField(name="relateTaskId")
-	public int relateTaskId;
-
-	@Override
- 	public String toString(){
-		return 
-			"TaskInfo{" + 
-			"args = '" + args + '\'' + 
-			",relateTaskId = '" + relateTaskId + '\'' + 
-			"}";
-		}
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/tools/Time.java b/android/sdk/src/main/java/com/taobao/weex/utils/tools/Time.java
deleted file mode 100644
index edeab93..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/tools/Time.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.tools;
-
-import com.alibaba.fastjson.annotation.JSONField;
-
-public class Time {
-
-    @JSONField(name = "taskStart")
-    public long taskStart;
-
-    @JSONField(name = "execTime")
-    public long execTime;
-
-    @JSONField(name = "constructor")
-    public long constructor;
-
-    @JSONField(name = "destructor")
-    public long destructor;
-
-    @JSONField(name = "taskEnd")
-    public long taskEnd;
-
-    @JSONField(name = "waitTime")
-    public long waitTime;
-
-    @Override
-    public String toString() {
-        return
-                "time : {" +
-                        "constructor = '" + constructor + '\'' +
-                        ",taskStart = '" + taskStart + '\'' +
-                        ",execTime = '" + execTime + '\'' +
-                        ",waitTime = '" + waitTime + '\'' +
-                        ",destructor = '" + destructor + '\'' +
-                        ",taskEnd = '" + taskEnd + '\'' +
-                        "}";
-    }
-
-
-    protected void constructor() {
-        constructor = System.currentTimeMillis();
-    }
-
-    public void execTime() {
-        execTime = taskEnd - taskStart;
-    }
-
-    public void taskStart() {
-        taskStart = System.currentTimeMillis();
-    }
-
-    public void taskEnd() {
-        taskEnd = System.currentTimeMillis();
-        execTime();
-        destructor();
-    }
-
-    private void destructor() {
-        waitTime();
-        destructor = System.currentTimeMillis();
-    }
-
-    public void waitTime() {
-        waitTime = taskStart - constructor;
-    }
-}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/tools/TimeCalculator.java b/android/sdk/src/main/java/com/taobao/weex/utils/tools/TimeCalculator.java
deleted file mode 100644
index 1e3eb2d..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/utils/tools/TimeCalculator.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils.tools;
-
-import android.util.Log;
-
-import com.alibaba.fastjson.JSON;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public class TimeCalculator {
-
-    public static final String TIMELINE_TAG = "timeline";
-
-    public static final String PLATFORM_ANDROID = "Android";
-
-    private CopyOnWriteArrayList<LogDetail> logRecorder;
-    public TimeCalculator(WXSDKInstance instance) {
-        logRecorder = new CopyOnWriteArrayList<LogDetail>();
-    }
-
-    public void addLog(LogDetail logDetail) {
-        if(!WXEnvironment.isPerf()) {
-            return;
-        }
-        logRecorder.add(logDetail);
-    }
-
-    public LogDetail createLogDetail(String name) {
-        LogDetail logDetail = new LogDetail();
-        logDetail.name(name);
-        addLog(logDetail);
-        return logDetail;
-    }
-
-    public void println() {
-        if(!WXEnvironment.isPerf()) {
-            return;
-        }
-
-        for (LogDetail l: logRecorder) {
-            Log.e(TIMELINE_TAG, JSON.toJSONString(l));
-        }
-
-    }
-
-
-    private String test = "{\"time\":{\"execTime\":0,\"constructor\":0,\"destructor\":0,\"taskStart\":0,\"taskEnd\":0,\"waitTime\":0},\"Info\":{\"taskInfo\":{\"relateTaskId\":0,\"args\":\"stringReplace\"},\"taskName\":\"stringReplace\",\"instanceId\":\"1\",\"platform\":\"stringReplace\",\"taskId\":0}}";
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/wson/Wson.java b/android/sdk/src/main/java/com/taobao/weex/wson/Wson.java
deleted file mode 100644
index b8b8992..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/wson/Wson.java
+++ /dev/null
@@ -1,820 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.wson;
-
-
-import android.support.v4.util.LruCache;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.annotation.JSONField;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * fast binary json format for parse map and serialize map
- * Created by efurture on 2017/8/16.
- */
-public class Wson {
-
-    /**
-     * skip map null values
-     * */
-    public static final boolean WriteMapNullValue = false;
-    /**
-     * wson data type
-     * */
-    private static final byte NULL_TYPE = '0';
-
-    private static final byte STRING_TYPE = 's';
-
-    private static final byte BOOLEAN_TYPE_TRUE = 't';
-
-    private static final byte BOOLEAN_TYPE_FALSE = 'f';
-
-    private static final byte NUMBER_INT_TYPE = 'i';
-
-    private static final byte NUMBER_LONG_TYPE = 'l';
-
-    private static final byte NUMBER_BIG_INTEGER_TYPE = 'g';
-
-    private static final byte NUMBER_BIG_DECIMAL_TYPE = 'e';
-
-    private static final byte NUMBER_DOUBLE_TYPE = 'd';
-
-    private static final byte NUMBER_FLOAT_TYPE = 'F';
-
-    private static final byte ARRAY_TYPE = '[';
-
-    private static final byte MAP_TYPE = '{';
-
-    /**
-     * StringUTF-16, byte order with native byte order
-     * */
-    private static final boolean IS_NATIVE_LITTLE_ENDIAN = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
-
-
-    /**
-     * parse wson data  to object, please use WXJsonUtils.parseWson
-     * @param  data  byte array
-     * */
-    public static final Object parse(byte[] data){
-        if(data == null){
-            return  null;
-        }
-        try{
-            Parser parser =  new Parser(data);
-            Object object = parser.parse();
-            parser.close();
-            return object;
-        }catch (Exception e){
-            WXLogUtils.e("parseWson", e);
-            return  null;
-        }
-    }
-
-
-    /**
-     * serialize object to wson data, please use WXJsonUtils.toWsonOrJsonWXJSObject
-     * */
-    public static final byte[] toWson(Object object){
-        if(object == null){
-            return  null;
-        }
-        Builder builder = new Builder();
-        byte[]  bts  = builder.toWson(object);
-        builder.close();
-        return bts;
-    }
-
-
-    /**
-     * wson data parser
-     * */
-    private static final class Parser {
-
-        private int position = 0;
-        private byte[] buffer;
-        private char[]  charsBuffer;
-
-        private Parser(byte[] buffer) {
-            this.buffer = buffer;
-            charsBuffer = localCharsBufferCache.get();
-            if(charsBuffer != null){
-                localCharsBufferCache.set(null);
-            }else{
-                charsBuffer = new char[512];
-            }
-        }
-
-
-        private   final Object parse(){
-            return  readObject();
-        }
-
-        private final void close(){
-            position = 0;
-            buffer = null;
-            if(charsBuffer != null){
-                localCharsBufferCache.set(charsBuffer);
-            }
-            charsBuffer = null;
-        }
-
-        private final Object readObject(){
-            byte type  = readType();
-            switch (type){
-                case STRING_TYPE:
-                    return readUTF16String();
-                case NUMBER_INT_TYPE :
-                    return  readVarInt();
-                case NUMBER_FLOAT_TYPE :
-                    return  readFloat();
-                case MAP_TYPE:
-                    return readMap();
-                case ARRAY_TYPE:
-                    return readArray();
-                case NUMBER_DOUBLE_TYPE :
-                    return readDouble();
-                case NUMBER_LONG_TYPE :
-                    return  readLong();
-                case NUMBER_BIG_INTEGER_TYPE :
-                    return  new BigInteger(readUTF16String());
-                case NUMBER_BIG_DECIMAL_TYPE :
-                    return  new BigDecimal(readUTF16String());
-                case BOOLEAN_TYPE_FALSE:
-                    return  Boolean.FALSE;
-                case BOOLEAN_TYPE_TRUE:
-                    return  Boolean.TRUE;
-                case NULL_TYPE:
-                    return  null;
-                default:
-                    throw new RuntimeException("wson unhandled type " + type + " " +
-                            position  +  " length " + buffer.length);
-            }
-        }
-
-
-
-        private final Object readMap(){
-            int size = readUInt();
-            Map<String, Object> object = new JSONObject();;
-            for(int i=0; i<size; i++){
-                String key = readMapKeyUTF16();
-                Object value = readObject();
-                object.put(key, value);
-            }
-            return object;
-        }
-
-        private final Object readArray(){
-            int length = readUInt();
-            List<Object> array = new JSONArray(length);
-            for(int i=0; i<length; i++){
-                array.add(readObject());
-            }
-            return  array;
-        }
-
-        private  final byte readType(){
-            byte type = buffer[position];
-            position ++;
-            return  type;
-        }
-
-
-        private final String readMapKeyUTF16() {
-            int length = readUInt();
-            length = length/2;
-            if(charsBuffer.length < length){
-                charsBuffer = new char[length];
-            }
-            int hash = 5381;
-            if(IS_NATIVE_LITTLE_ENDIAN){
-                for(int i=0; i<length; i++){
-                    char ch = (char) ((buffer[position] & 0xFF) +
-                            (buffer[position + 1] << 8));
-                    charsBuffer[i] = (ch);
-                    hash = ((hash << 5) + hash)  + ch;
-                    position+=2;
-                }
-            }else{
-                for(int i=0; i<length; i++){
-                    char ch = (char) ((buffer[position + 1] & 0xFF) +
-                            (buffer[position] << 8));
-                    charsBuffer[i] = (ch);
-                    hash = ((hash << 5) + hash)  + ch;
-                    position+=2;
-                }
-            }
-            int globalIndex = (globalStringBytesCache.length - 1)&hash;
-            String cache = globalStringBytesCache[globalIndex];
-            if(cache != null
-                    && cache.length() == length){
-                boolean isStringEqual  = true;
-                for(int i=0; i<length; i++){
-                    if(charsBuffer[i] != cache.charAt(i)){
-                        isStringEqual = false;
-                        break;
-                    }
-                }
-                if(isStringEqual) {
-                    return cache;
-                }
-            }
-            cache = new String(charsBuffer, 0, length);
-            if(length < 64) {
-                globalStringBytesCache[globalIndex] = cache;
-            }
-            return  cache;
-        }
-
-        private final String readUTF16String(){
-            int length = readUInt()/2;
-            if(charsBuffer.length < length){
-                charsBuffer = new char[length];
-            }
-            if(IS_NATIVE_LITTLE_ENDIAN){
-                for(int i=0; i<length; i++){
-                    char ch = (char) ((buffer[position] & 0xFF) +
-                            (buffer[position + 1] << 8));
-                    charsBuffer[i] = (ch);
-                    position+=2;
-                }
-            }else{
-                for(int i=0; i<length; i++){
-                    char ch = (char) ((buffer[position + 1] & 0xFF) +
-                            (buffer[position] << 8));
-                    charsBuffer[i] = (ch);
-                    position+=2;
-                }
-            }
-            return  new String(charsBuffer, 0, length);
-        }
-
-
-
-
-
-        private   final int readVarInt(){
-            int raw = readUInt();
-            // This undoes the trick in putVarInt()
-            int num = (((raw << 31) >> 31) ^ raw) >> 1;
-            // This extra step lets us deal with the largest signed values by treating
-            // negative results from read unsigned methods as like unsigned values.
-            // Must re-flip the top bit if the original read value had it set.
-            return num ^ (raw & (1 << 31));
-        }
-
-        private final  int readUInt(){
-            int value = 0;
-            int i = 0;
-            int b;
-            while (((b = buffer[position]) & 0x80) != 0) {
-                value |= (b & 0x7F) << i;
-                i += 7;
-                position+=1;
-                if (i > 35) {
-                    throw new IllegalArgumentException("Variable length quantity is too long");
-                }
-            }
-            position+=1;
-            return value | (b << i);
-        }
-
-        private final long readLong(){
-            long number = (((buffer[position + 7] & 0xFFL)      ) +
-                    ((buffer[position + 6] & 0xFFL) <<  8) +
-                    ((buffer[position + 5] & 0xFFL) << 16) +
-                    ((buffer[position + 4] & 0xFFL) << 24) +
-                    ((buffer[position + 3] & 0xFFL) << 32) +
-                    ((buffer[position + 2] & 0xFFL) << 40) +
-                    ((buffer[position + 1] & 0xFFL) << 48) +
-                    (((long) buffer[position])      << 56));
-            position += 8;
-            return  number;
-        }
-
-        private  final Object readDouble(){
-            double number = Double.longBitsToDouble(readLong());
-            if(number > Integer.MAX_VALUE){
-                long numberLong = (long) number;
-                double doubleLong = (numberLong);
-                if(number - doubleLong < Double.MIN_NORMAL){
-                    return numberLong;
-                }
-            }
-            return  number;
-        }
-
-        private Object readFloat() {
-            int number = (((buffer[position + 3] & 0xFF)      ) +
-                    ((buffer[position + 2] & 0xFF) <<  8) +
-                    ((buffer[position + 1] & 0xFF) << 16) +
-                    ((buffer[position  ] & 0xFF) << 24));
-            position +=4;
-            return  Float.intBitsToFloat(number);
-        }
-    }
-
-    /**
-     * wson builder
-     * */
-    private static final class Builder {
-
-        private byte[] buffer;
-        private int position;
-        private ArrayList refs;
-        private final static ThreadLocal<byte[]> bufLocal = new ThreadLocal<byte[]>();
-        private final static ThreadLocal<ArrayList> refsLocal = new ThreadLocal<ArrayList>();
-
-
-
-        private Builder(){
-            buffer =  bufLocal.get();
-            if(buffer != null) {
-                bufLocal.set(null);
-            }else{
-                buffer = new byte[1024];
-            }
-            refs = refsLocal.get();
-            if(refs != null){
-                refsLocal.set(null);
-            }else{
-                refs = new ArrayList<>(16);
-            }
-        }
-
-
-        private final byte[] toWson(Object object){
-            writeObject(object);
-            byte[] bts = new byte[position];
-            System.arraycopy(buffer, 0, bts, 0, position);
-            return  bts;
-        }
-
-        private final void close(){
-            if(buffer.length <= 1024*16){
-                bufLocal.set(buffer);
-            }
-            if(refs.isEmpty()){
-                refsLocal.set(refs);
-            }else{
-                refs.clear();
-            }
-            refs = null;
-            buffer = null;
-            position = 0;
-        }
-
-        private final void writeObject(Object object) {
-            if(object instanceof  CharSequence){
-                ensureCapacity(2);
-                writeByte(STRING_TYPE);
-                writeUTF16String((CharSequence) object);
-                return;
-            }else if (object instanceof Map){
-                if(refs.contains(object)){
-                    ensureCapacity(2);
-                    writeByte(NULL_TYPE);
-                    return;
-                }
-                refs.add(object);
-                Map map = (Map) object;
-                writeMap(map);
-                refs.remove(refs.size()-1);
-                return;
-            }else if (object instanceof List){
-                if(refs.contains(object)){
-                    ensureCapacity(2);
-                    writeByte(NULL_TYPE);
-                    return;
-                }
-                refs.add(object);
-                ensureCapacity(8);
-                List list = (List) object;
-                writeByte(ARRAY_TYPE);
-                writeUInt(list.size());
-                for(Object value : list){
-                    writeObject(value);
-                }
-                refs.remove(refs.size()-1);
-                return;
-            }else if (object instanceof Number){
-                Number number = (Number) object;
-                writeNumber(number);
-                return;
-            }else if (object instanceof  Boolean){
-                ensureCapacity(2);
-                Boolean value  = (Boolean) object;
-                if(value){
-                    writeByte(BOOLEAN_TYPE_TRUE);
-                }else{
-                    writeByte(BOOLEAN_TYPE_FALSE);
-                }
-                return;
-            }else if(object == null){
-                ensureCapacity(2);
-                writeByte(NULL_TYPE);
-                return;
-            }else if (object.getClass().isArray()){
-                if(refs.contains(object)){
-                    ensureCapacity(2);
-                    writeByte(NULL_TYPE);
-                    return;
-                }
-                refs.add(object);
-                ensureCapacity(8);
-                int length = Array.getLength(object);
-                writeByte(ARRAY_TYPE);
-                writeUInt(length);
-                for(int i=0; i<length; i++){
-                    Object value = Array.get(object, i);
-                    writeObject(value);
-                }
-                refs.remove(refs.size()-1);
-                return;
-            }else  if(object instanceof  Date){
-                ensureCapacity(10);
-                double date = ((Date)object).getTime();
-                writeByte(NUMBER_DOUBLE_TYPE);
-                writeDouble(date);
-            }else  if(object instanceof  Calendar){
-                ensureCapacity(10);
-                double date = ((Calendar)object).getTime().getTime();
-                writeByte(NUMBER_DOUBLE_TYPE);
-                writeDouble(date);
-            }else  if(object instanceof  Collection){
-                if(refs.contains(object)){
-                    ensureCapacity(2);
-                    writeByte(NULL_TYPE);
-                    return;
-                }
-                refs.add(object);
-                ensureCapacity(8);
-                Collection list = (Collection) object;
-                writeByte(ARRAY_TYPE);
-                writeUInt(list.size());
-                for(Object value : list){
-                    writeObject(value);
-                }
-                refs.remove(refs.size()-1);
-            }else{
-                if(refs.contains(object)){
-                    ensureCapacity(2);
-                    writeByte(NULL_TYPE);
-                }else {
-                    refs.add(object);
-                    if(object.getClass().isEnum()){
-                        writeObject(JSON.toJSONString(object));
-                    }else{
-                        writeAdapterObject(object);
-                    }
-                    refs.remove(refs.size()-1);
-                }
-                return;
-            }
-        }
-
-        private final void writeNumber(Number number) {
-            ensureCapacity(12);
-            if(number instanceof  Integer){
-                writeByte(NUMBER_INT_TYPE);
-                writeVarInt(number.intValue());
-                return;
-            }
-
-            if(number instanceof Float){
-                writeByte(NUMBER_FLOAT_TYPE);
-                writeFloat(number.floatValue());
-                return;
-            }
-            if(number instanceof  Double){
-                writeByte(NUMBER_DOUBLE_TYPE);
-                writeDouble(number.doubleValue());
-                return;
-            }
-
-            if(number instanceof  Long){
-                writeByte(NUMBER_LONG_TYPE);
-                writeLong(number.longValue());
-                return;
-            }
-
-            if(number instanceof  Short
-                    || number instanceof  Byte){
-                writeByte(NUMBER_INT_TYPE);
-                writeVarInt(number.intValue());
-                return;
-            }
-
-            if(number instanceof BigInteger){
-                writeByte(NUMBER_BIG_INTEGER_TYPE);
-                writeUTF16String(number.toString());
-                return;
-            }
-
-            if(number instanceof BigDecimal){
-                String value = number.toString();
-                double doubleValue = number.doubleValue();
-                if(value.equals(Double.toString(doubleValue))){
-                    writeByte(NUMBER_DOUBLE_TYPE);
-                    writeDouble(doubleValue);
-                }else {
-                    writeByte(NUMBER_BIG_DECIMAL_TYPE);
-                    writeUTF16String(value);
-                }
-                return;
-            }
-            writeByte(STRING_TYPE);
-            writeUTF16String(number.toString());
-
-        }
-
-        private final  void writeMap(Map map) {
-            if(WriteMapNullValue){
-                ensureCapacity(8);
-                writeByte(MAP_TYPE);
-                writeUInt(map.size());
-                Set<Map.Entry<Object,Object>>  entries = map.entrySet();
-                for(Map.Entry<Object,Object> entry : entries){
-                    writeMapKeyUTF16(entry.getKey().toString());
-                    writeObject(entry.getValue());
-                }
-            }else{
-                Set<Map.Entry<Object,Object>>  entries = map.entrySet();
-                int nullValueSize = 0;
-                for(Map.Entry<Object,Object> entry : entries){
-                    if(entry.getValue() == null){
-                        nullValueSize++;
-                    }
-                }
-
-                ensureCapacity(8);
-                writeByte(MAP_TYPE);
-                writeUInt(map.size()-nullValueSize);
-                for(Map.Entry<Object,Object> entry : entries){
-                    if(entry.getValue() == null){
-                        continue;
-                    }
-                    writeMapKeyUTF16(entry.getKey().toString());
-                    writeObject(entry.getValue());
-                }
-            }
-        }
-
-
-        private final void writeByte(byte type){
-            buffer[position] = type;
-            position++;
-        }
-
-        private final void writeAdapterObject(Object object){
-            if(specialClass.get(object.getClass().getName()) != null){
-                writeObject(JSON.toJSON(object));
-                return;
-            }
-            try{
-                writeMap(toMap(object));
-            }catch (Exception e){
-                specialClass.put(object.getClass().getName(), true);
-                writeObject(JSON.toJSON(object));
-            }
-        }
-
-        private  final Map  toMap(Object object){
-            Map map = new JSONObject();
-            try {
-                Class<?> targetClass = object.getClass();
-                String key = targetClass.getName();
-                List<Method> methods = getBeanMethod(key, targetClass);
-                for (Method method : methods) {
-                    String methodName = method.getName();
-                    if (methodName.startsWith(METHOD_PREFIX_GET)) {
-                        Object value = method.invoke(object);
-                        if(value != null){
-                            StringBuilder builder = new StringBuilder(method.getName().substring(3));
-                            builder.setCharAt(0, Character.toLowerCase(builder.charAt(0)));
-                            map.put(builder.toString(), (Object) value);
-                        }
-                    }else if(methodName.startsWith(METHOD_PREFIX_IS)){
-                        Object value = method.invoke(object);
-                        if(value != null){
-                            StringBuilder builder = new StringBuilder(method.getName().substring(2));
-                            builder.setCharAt(0, Character.toLowerCase(builder.charAt(0)));
-                            map.put(builder.toString(), value);
-                        }
-                    }
-                }
-                List<Field> fields = getBeanFields(key, targetClass);
-                for(Field field : fields){
-                    String fieldName = field.getName();
-                    if(map.containsKey(fieldName)){
-                        continue;
-                    }
-                    Object value  = field.get(object);
-                    if(value == null){
-                        continue;
-                    }
-                    map.put(fieldName, value);
-                }
-            }catch (Exception e){
-                if(e instanceof  RuntimeException){
-                    throw  (RuntimeException)e;
-                }else{
-                    throw  new RuntimeException(e);
-                }
-            }
-            return  map;
-        }
-
-        private  final void writeMapKeyUTF16(String value){
-            writeUTF16String(value);
-        }
-
-
-
-
-        /**
-         * writeString UTF-16
-         * */
-        private  final void writeUTF16String(CharSequence value){
-            int length = value.length();
-            ensureCapacity(length*2 + 8);
-            writeUInt(length*2);
-            if(IS_NATIVE_LITTLE_ENDIAN){
-                for(int i=0; i<length; i++){
-                    char ch = value.charAt(i);
-                    buffer[position] = (byte) (ch);
-                    buffer[position+1] = (byte) (ch >>> 8);
-                    position+=2;
-                }
-            }else{
-                for(int i=0; i<length; i++){
-                    char ch = value.charAt(i);
-                    buffer[position + 1] = (byte) (ch      );
-                    buffer[position] = (byte) (ch >>> 8);
-                    position+=2;
-                }
-            }
-        }
-
-
-        private final void writeDouble(double value){
-            writeLong(Double.doubleToLongBits(value));
-        }
-
-        private final void writeFloat(float value){
-            int val = Float.floatToIntBits(value);
-            buffer[position + 3] = (byte) (val       );
-            buffer[position + 2] = (byte) (val >>>  8);
-            buffer[position + 1] = (byte) (val >>> 16);
-            buffer[position ] = (byte) (val >>> 24);
-            position += 4;
-        }
-
-        private final void writeLong(long val){
-            buffer[position + 7] = (byte) (val       );
-            buffer[position + 6] = (byte) (val >>>  8);
-            buffer[position + 5] = (byte) (val >>> 16);
-            buffer[position + 4] = (byte) (val >>> 24);
-            buffer[position + 3] = (byte) (val >>> 32);
-            buffer[position + 2] = (byte) (val >>> 40);
-            buffer[position + 1] = (byte) (val >>> 48);
-            buffer[position    ] = (byte) (val >>> 56);
-            position += 8;
-        }
-
-        private final void writeVarInt(int value){
-            writeUInt((value << 1) ^ (value >> 31));
-        }
-
-        private final void  writeUInt(int value){
-            while ((value & 0xFFFFFF80) != 0) {
-                buffer[position] = (byte)((value & 0x7F) | 0x80);
-                position++;
-                value >>>= 7;
-            }
-            buffer[position] = (byte)(value & 0x7F);
-            position++;
-        }
-
-
-        private final void ensureCapacity(int minCapacity) {
-            minCapacity += position;
-            // overflow-conscious code
-            if (minCapacity - buffer.length > 0){
-                int oldCapacity = buffer.length;
-                int newCapacity = oldCapacity << 1;
-                if(newCapacity < 1024*16){
-                    newCapacity = 1024*16;
-                }
-                if (newCapacity - minCapacity < 0) {
-                    newCapacity = minCapacity;
-                }
-                buffer = Arrays.copyOf(buffer, newCapacity);
-            }
-        }
-    }
-
-
-    /**
-     * cache json property key, most of them all same
-     * */
-    private static final int GLOBAL_STRING_CACHE_SIZE = 2*1024;
-    private static final ThreadLocal<char[]> localCharsBufferCache = new ThreadLocal<>();
-    private static final String[] globalStringBytesCache = new String[GLOBAL_STRING_CACHE_SIZE];
-
-
-
-
-    /**
-     * lru cache, to map helper
-     * */
-    private static final String METHOD_PREFIX_GET = "get";
-    private static final String METHOD_PREFIX_IS = "is";
-    private static LruCache<String, List<Method>> methodsCache = new LruCache<>(128);
-    private static LruCache<String, List<Field>> fieldsCache = new LruCache<>(128);
-    private static LruCache<String, Boolean> specialClass = new LruCache<>(16);
-
-
-    private static final List<Method> getBeanMethod(String key, Class targetClass){
-        List<Method> methods = methodsCache.get(key);
-        if(methods == null){
-            methods = new ArrayList<>();
-            Method[]  allMethods = targetClass.getMethods();
-            for(Method method : allMethods){
-                if(method.getDeclaringClass() == Object.class){
-                    continue;
-                }
-                if( (method.getModifiers() & Modifier.STATIC) != 0){
-                    continue;
-                }
-                String methodName = method.getName();
-                if(methodName.startsWith(METHOD_PREFIX_GET)
-                        || methodName.startsWith(METHOD_PREFIX_IS)) {
-                    if(method.getAnnotation(JSONField.class) != null){
-                        throw new UnsupportedOperationException("getBeanMethod JSONField Annotation Not Handled, Use toJSON");
-                    }
-                    methods.add(method);
-                }
-            }
-            methodsCache.put(key, methods);
-        }
-        return methods;
-    }
-
-
-
-    private static  final List<Field> getBeanFields(String key, Class targetClass){
-        List<Field> fieldList = fieldsCache.get(key);
-        if(fieldList == null) {
-            Field[] fields = targetClass.getFields();
-            fieldList = new ArrayList<>(fields.length);
-            for(Field field : fields){
-                if((field.getModifiers() & Modifier.STATIC) != 0){
-                    continue;
-                }
-                if(field.getAnnotation(JSONField.class) != null){
-                    throw new UnsupportedOperationException("getBeanMethod JSONField Annotation Not Handled, Use toJSON");
-                }
-                fieldList.add(field);
-            }
-            fieldsCache.put(key, fieldList);
-        }
-        return  fieldList;
-    }
-
-}
diff --git a/android/sdk/src/main/java/com/taobao/weex/wson/WsonUtils.java b/android/sdk/src/main/java/com/taobao/weex/wson/WsonUtils.java
deleted file mode 100644
index dc51438..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/wson/WsonUtils.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.wson;
-
-import com.taobao.weex.utils.WXLogUtils;
-
-/**
- * Created by furture on 2018/5/17.
- */
-
-public class WsonUtils {
-    /**
-     * total entry, with wson support, always parse json
-     * */
-    public static final Object parseWson(byte[] data){
-        if(data == null){
-            return  null;
-        }
-        try{
-            return  Wson.parse(data);
-        }catch (Exception e){
-            WXLogUtils.e("weex wson parse error ", e);
-            return  null;
-        }
-    }
-
-    public static final byte[] toWson(Object data){
-        if(data == null){
-            return  null;
-        }
-        try{
-            return  Wson.toWson(data);
-        }catch (Exception e){
-            WXLogUtils.e("weex wson to wson error ", e);
-            return  null;
-        }
-    }
-}
diff --git a/android/sdk/src/main/java/org/apache/weex/ComponentObserver.java b/android/sdk/src/main/java/org/apache/weex/ComponentObserver.java
new file mode 100644
index 0000000..f77eb7e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ComponentObserver.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.view.View;
+
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by sospartan on 14/06/2017.
+ */
+
+public interface ComponentObserver {
+
+  /**
+   * Called after component is create.
+   * Notice: View is not created at this moment.
+   * @param component
+   */
+  void onCreate(WXComponent component);
+
+  /**
+   * Called before component destroy.
+   * @param component
+   */
+  void onPreDestory(WXComponent component);
+
+  /**
+   * Called when component's view is created
+   * @param component
+   * @param view
+   */
+  void onViewCreated(WXComponent component,View view);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/IWXActivityStateListener.java b/android/sdk/src/main/java/org/apache/weex/IWXActivityStateListener.java
new file mode 100644
index 0000000..0398aec
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/IWXActivityStateListener.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+/**
+ * Listener class for activity lifecycle
+ */
+
+@Deprecated
+public interface IWXActivityStateListener {
+
+  void onActivityCreate();
+
+  void onActivityStart();
+
+  void onActivityPause();
+
+  void onActivityResume();
+
+  void onActivityStop();
+
+  void onActivityDestroy();
+
+  boolean onActivityBack();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/IWXRenderListener.java b/android/sdk/src/main/java/org/apache/weex/IWXRenderListener.java
new file mode 100644
index 0000000..82f70fa
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/IWXRenderListener.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.view.View;
+import org.apache.weex.common.WXRenderStrategy;
+
+public interface IWXRenderListener {
+
+  /**
+   * If {@link WXRenderStrategy#APPEND_ASYNC} is applied, this method
+   * will be invoked when the rendering of first view is finish.
+   * If {@link WXRenderStrategy#APPEND_ONCE} is applied, this method will
+   * be invoked when the rendering of the view tree is finished.
+   */
+  void onViewCreated(WXSDKInstance instance, View view);
+
+  /**
+   * Called when the render view phase of weex has finished.
+   * It can be invoked at most once in the entire life of a {@link WXSDKInstance}
+   */
+  void onRenderSuccess(WXSDKInstance instance, int width, int height);
+
+  /**
+   * Callback method, called when refresh is finished
+   */
+  void onRefreshSuccess(WXSDKInstance instance, int width, int height);
+
+  /**
+   * Report exception occurred when weex instance is running. Exception <strong>may not</strong>
+   * cause user-noticeable failure of weex.
+   */
+  void onException(WXSDKInstance instance, String errCode, String msg);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/IWXStatisticsListener.java b/android/sdk/src/main/java/org/apache/weex/IWXStatisticsListener.java
new file mode 100644
index 0000000..580b02a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/IWXStatisticsListener.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+public interface IWXStatisticsListener {
+  /**
+   * Called when weex sdk engine begin to initialize.
+   */
+   void onSDKEngineInitialize();
+
+  /**
+   * Called when begin to load js framework.
+   */
+   void onJsFrameworkStart();
+
+  /**
+   * Called when finish loading js framework.
+   */
+   void onJsFrameworkReady();
+
+  /**
+   * Called when the render view phase of first view reached.
+   */
+   void onFirstView();
+
+  /**
+   * Called when the render view phase of first screen reached.
+   */
+  void onFirstScreen();
+
+  /**
+   * Called when to start a http request.
+   */
+  void onHttpStart();
+
+  /**
+   * Called when received a http response header data.
+   */
+  void onHeadersReceived();
+
+  /**
+   * Called when to finish a http request.
+   */
+  void onHttpFinish();
+
+  /**
+   * Called when an exception occured.
+   */
+  void onException(String instanceid, String errCode, String msg);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/InitConfig.java b/android/sdk/src/main/java/org/apache/weex/InitConfig.java
new file mode 100644
index 0000000..911271b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/InitConfig.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.support.annotation.NonNull;
+import org.apache.weex.adapter.ClassLoaderAdapter;
+import org.apache.weex.adapter.IDrawableLoader;
+import org.apache.weex.adapter.IWXHttpAdapter;
+import org.apache.weex.adapter.IWXImgLoaderAdapter;
+import org.apache.weex.adapter.IWXJSExceptionAdapter;
+import org.apache.weex.adapter.IWXJsFileLoaderAdapter;
+import org.apache.weex.adapter.IWXJscProcessManager;
+import org.apache.weex.adapter.IWXSoLoaderAdapter;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.appfram.storage.IWXStorageAdapter;
+import org.apache.weex.appfram.websocket.IWebSocketAdapterFactory;
+import org.apache.weex.performance.IApmGenerator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created by sospartan on 5/31/16.
+ */
+public class InitConfig {
+  private IWXHttpAdapter httpAdapter;
+  private IDrawableLoader drawableLoader;
+  private IWXImgLoaderAdapter imgAdapter;
+  private IWXUserTrackAdapter utAdapter;
+  private IWXStorageAdapter storageAdapter;
+  private IWXSoLoaderAdapter soLoader;
+  private URIAdapter mURIAdapter;
+  private IWebSocketAdapterFactory webSocketAdapterFactory;
+  private IWXJSExceptionAdapter mJSExceptionAdapter;
+  private String framework;
+  private ClassLoaderAdapter classLoaderAdapter;
+  private IApmGenerator apmGenerater;
+  private IWXJsFileLoaderAdapter jsFileLoaderAdapter;
+  private IWXJscProcessManager jscProcessManager;
+  private List<String> nativeLibraryList;
+
+  public IWXHttpAdapter getHttpAdapter() {
+    return httpAdapter;
+  }
+
+  public IWXImgLoaderAdapter getImgAdapter() {
+    return imgAdapter;
+  }
+
+  public IDrawableLoader getDrawableLoader() {
+    return drawableLoader;
+  }
+
+  public IWXUserTrackAdapter getUtAdapter() {
+    return utAdapter;
+  }
+
+  public IWXSoLoaderAdapter getIWXSoLoaderAdapter() {
+    return soLoader;
+  }
+
+  public String getFramework() {
+    return framework;
+  }
+
+  public IWXStorageAdapter getStorageAdapter() {
+    return storageAdapter;
+  }
+
+  public URIAdapter getURIAdapter() {
+    return mURIAdapter;
+  }
+
+  public IWebSocketAdapterFactory getWebSocketAdapterFactory() {
+    return webSocketAdapterFactory;
+  }
+
+  public ClassLoaderAdapter getClassLoaderAdapter() {
+    return classLoaderAdapter;
+  }
+
+  public IApmGenerator getApmGenerater() {
+    return apmGenerater;
+  }
+
+  public IWXJsFileLoaderAdapter getJsFileLoaderAdapter() {
+    return jsFileLoaderAdapter;
+  }
+
+  public InitConfig setClassLoaderAdapter(ClassLoaderAdapter classLoaderAdapter) {
+    this.classLoaderAdapter = classLoaderAdapter;
+    return this;
+  }
+
+  public IWXJSExceptionAdapter getJSExceptionAdapter() {
+    return mJSExceptionAdapter;
+  }
+  public IWXJscProcessManager getJscProcessManager() {
+    return jscProcessManager;
+  }
+
+  @NonNull Iterable<String> getNativeLibraryList() {
+    if(nativeLibraryList == null){
+      nativeLibraryList = new LinkedList<>();
+    }
+    return nativeLibraryList;
+  }
+
+  private InitConfig() {
+  }
+
+  public static class Builder{
+    IWXHttpAdapter httpAdapter;
+    IWXImgLoaderAdapter imgAdapter;
+    IDrawableLoader drawableLoader;
+    IWXUserTrackAdapter utAdapter;
+    IWXStorageAdapter storageAdapter;
+    IWXSoLoaderAdapter soLoader;
+    URIAdapter mURIAdapter;
+    IWXJSExceptionAdapter mJSExceptionAdapter;
+    String framework;
+    IWebSocketAdapterFactory webSocketAdapterFactory;
+    ClassLoaderAdapter classLoaderAdapter;
+    IApmGenerator apmGenerater;
+    private IWXJsFileLoaderAdapter jsFileLoaderAdapter;
+    private List<String> nativeLibraryList = new LinkedList<>();
+
+    public IWXJscProcessManager getJscProcessManager() {
+      return jscProcessManager;
+    }
+
+    public Builder setJscProcessManager(IWXJscProcessManager jscProcessManager) {
+      this.jscProcessManager = jscProcessManager;
+      return this;
+    }
+
+    IWXJscProcessManager jscProcessManager;
+
+    public Builder(){
+
+    }
+
+    public Builder setHttpAdapter(IWXHttpAdapter httpAdapter) {
+      this.httpAdapter = httpAdapter;
+      return this;
+    }
+
+    public Builder setImgAdapter(IWXImgLoaderAdapter imgAdapter) {
+      this.imgAdapter = imgAdapter;
+      return this;
+    }
+
+    public Builder setDrawableLoader(IDrawableLoader drawableLoader){
+      this.drawableLoader=drawableLoader;
+      return this;
+    }
+
+    public Builder setUtAdapter(IWXUserTrackAdapter utAdapter) {
+      this.utAdapter = utAdapter;
+      return this;
+    }
+
+    public Builder setStorageAdapter(IWXStorageAdapter storageAdapter) {
+      this.storageAdapter = storageAdapter;
+      return this;
+    }
+
+    public Builder setURIAdapter(URIAdapter URIAdapter) {
+      mURIAdapter = URIAdapter;
+      return this;
+    }
+
+    public Builder setJSExceptionAdapter(IWXJSExceptionAdapter JSExceptionAdapter) {
+      mJSExceptionAdapter = JSExceptionAdapter;
+      return this;
+    }
+
+    public Builder setSoLoader(IWXSoLoaderAdapter loader) {
+      this.soLoader = loader;
+      return this;
+    }
+
+    public Builder setFramework(String framework){
+      this.framework=framework;
+      return this;
+    }
+
+    public Builder setWebSocketAdapterFactory(IWebSocketAdapterFactory factory) {
+      this.webSocketAdapterFactory = factory;
+      return this;
+    }
+
+    public Builder setClassLoaderAdapter(ClassLoaderAdapter classLoaderAdapter) {
+      this.classLoaderAdapter = classLoaderAdapter;
+      return this;
+    }
+
+    public Builder setApmGenerater(IApmGenerator apmGenerater){
+      this.apmGenerater =apmGenerater;
+      return this;
+    }
+
+    public Builder setJsFileLoaderAdapter(IWXJsFileLoaderAdapter jsFileLoaderAdapter) {
+      this.jsFileLoaderAdapter = jsFileLoaderAdapter;
+      return this;
+    }
+
+    public Builder addNativeLibrary(String name){
+      nativeLibraryList.add(name);
+      return this;
+    }
+
+    public InitConfig build(){
+      InitConfig config =  new InitConfig();
+      config.httpAdapter = this.httpAdapter;
+      config.imgAdapter = this.imgAdapter;
+      config.drawableLoader = this.drawableLoader;
+      config.utAdapter = this.utAdapter;
+      config.storageAdapter = this.storageAdapter;
+      config.soLoader=this.soLoader;
+      config.framework=this.framework;
+      config.mURIAdapter = this.mURIAdapter;
+      config.webSocketAdapterFactory = this.webSocketAdapterFactory;
+      config.mJSExceptionAdapter=this.mJSExceptionAdapter;
+      config.classLoaderAdapter = this.classLoaderAdapter;
+      config.apmGenerater = this.apmGenerater;
+      config.jsFileLoaderAdapter = this.jsFileLoaderAdapter;
+      config.jscProcessManager = this.jscProcessManager;
+      config.nativeLibraryList = this.nativeLibraryList;
+      return config;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/RenderContainer.java b/android/sdk/src/main/java/org/apache/weex/RenderContainer.java
new file mode 100644
index 0000000..29af1b6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/RenderContainer.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+
+
+import org.apache.weex.render.WXAbstractRenderContainer;
+
+/**
+ * Created by sospartan on 08/10/2016.
+ */
+
+public class RenderContainer extends WXAbstractRenderContainer implements WeexFrameRateControl.VSyncListener{
+  private WeexFrameRateControl mFrameRateControl;
+
+  public RenderContainer(Context context) {
+    super(context);
+    mFrameRateControl = new WeexFrameRateControl(this);
+  }
+
+  public RenderContainer(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    mFrameRateControl = new WeexFrameRateControl(this);
+  }
+
+  public RenderContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+    super(context, attrs, defStyleAttr);
+    mFrameRateControl = new WeexFrameRateControl(this);
+  }
+
+  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+  public RenderContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    super(context, attrs, defStyleAttr, defStyleRes);
+    mFrameRateControl = new WeexFrameRateControl(this);
+  }
+
+
+
+  @Override
+  public void onAttachedToWindow() {
+    super.onAttachedToWindow();
+    if (mFrameRateControl != null) {
+      mFrameRateControl.start();
+    }
+  }
+
+  @Override
+  protected void onDetachedFromWindow() {
+    super.onDetachedFromWindow();
+    if (mFrameRateControl != null) {
+      mFrameRateControl.stop();
+    }
+  }
+  @Override
+  public void dispatchWindowVisibilityChanged(int visibility) {
+    super.dispatchWindowVisibilityChanged(visibility);
+    if (visibility == View.GONE) {
+      if (mFrameRateControl != null) {
+        mFrameRateControl.stop();
+      }
+    } else if (visibility == View.VISIBLE) {
+      if (mFrameRateControl != null) {
+        mFrameRateControl.start();
+      }
+    }
+  }
+
+  @Override
+  public void OnVSync() {
+    if (mSDKInstance != null && mSDKInstance.get() != null) {
+      mSDKInstance.get().OnVSync();
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/Script.java b/android/sdk/src/main/java/org/apache/weex/Script.java
new file mode 100644
index 0000000..6688fc3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/Script.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.text.TextUtils;
+
+public class Script {
+    private String mContent;
+    private byte[] mBinary;
+
+    public Script(String content) {
+        mContent = content;
+    }
+
+    public Script(byte[] binary) {
+        mBinary = binary;
+    }
+
+    public String getContent() {
+        return mContent;
+    }
+
+    public byte[] getBinary() {
+        return mBinary;
+    }
+
+    public int length() {
+        if (mContent != null) {
+            return mContent.length();
+        } else if (mBinary != null){
+            return mBinary.length;
+        }
+        return 0;
+    }
+
+    public boolean isEmpty() {
+        return TextUtils.isEmpty(mContent) && (mBinary == null || mBinary.length == 0);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/WXEnvironment.java b/android/sdk/src/main/java/org/apache/weex/WXEnvironment.java
new file mode 100644
index 0000000..dd467b3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WXEnvironment.java
@@ -0,0 +1,692 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import android.annotation.SuppressLint;
+import android.app.Application;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Typeface;
+import android.os.Environment;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import dalvik.system.PathClassLoader;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.weex.R;
+import org.apache.weex.common.WXConfig;
+import org.apache.weex.utils.FontDO;
+import org.apache.weex.utils.LogLevel;
+import org.apache.weex.utils.TypefaceUtil;
+import org.apache.weex.utils.WXFileUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXSoInstallMgrSdk;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+public class WXEnvironment {
+
+  public static final String OS = "android";
+  public static String SYS_VERSION = android.os.Build.VERSION.RELEASE;
+  static{
+    if(SYS_VERSION != null && SYS_VERSION.toUpperCase(Locale.ROOT).equals("P")){
+        SYS_VERSION = "9.0.0";
+    }
+    if(SYS_VERSION != null && SYS_VERSION.toUpperCase(Locale.ROOT).equals("Q")){
+       SYS_VERSION = "10.0.0";
+    }
+  }
+  public static final String SYS_MODEL = android.os.Build.MODEL;
+  public static final String EAGLE = "eagle";
+  public static final String ENVIRONMENT = "environment";
+  public static final String WEEX_CURRENT_KEY = "wx_current_url";
+  /*********************
+   * Global config
+   ***************************/
+
+  public static String JS_LIB_SDK_VERSION = BuildConfig.buildJavascriptFrameworkVersion;
+
+  public static String WXSDK_VERSION = BuildConfig.buildVersion;
+  public static Application sApplication;
+  public static final String DEV_Id = getDevId();
+  @Deprecated
+  public static int sDefaultWidth = 750;
+  public volatile static boolean JsFrameworkInit = false;
+
+  public static final String SETTING_EXCLUDE_X86SUPPORT = "env_exclude_x86";
+
+  public static boolean SETTING_FORCE_VERTICAL_SCREEN = false;
+
+  /**
+   * auto adjust device width for when screen size change.
+   * */
+  public static boolean AUTO_ADJUST_ENV_DEVICE_WIDTH = true;
+
+  public static boolean AUTO_UPDATE_APPLICATION_SCREEN_SIZE = true;
+
+  @RestrictTo(Scope.LIBRARY)
+  public static volatile boolean sUseRunTimeApi;
+
+  /**
+   * Debug model
+   */
+  public static boolean sDebugMode = false;
+  public static final boolean sForceEnableDevTool = true;
+  public static String sDebugWsUrl = "";
+  public static boolean sDebugServerConnectable = false;
+  public static boolean sRemoteDebugMode = false;
+  public static String sRemoteDebugProxyUrl = "";
+  public static boolean sDebugNetworkEventReporterEnable = false;//debugtool network switch
+  public static long sJSLibInitTime = 0;
+
+  public static long sSDKInitStart = 0;// init start timestamp
+  public static long sSDKInitInvokeTime = 0;//time cost to invoke init method
+  public static long sSDKInitExecuteTime = 0;//time cost to execute init job
+  /** from init to sdk-ready **/
+  public static long sSDKInitTime =0;
+
+  public static long sJSFMStartListenerTime=0;
+
+  public static volatile boolean isWsFixMode = true;
+
+  /**
+   * component and modules ready
+   * */
+  public static long sComponentsAndModulesReadyTime = 0;
+
+  public static boolean sInAliWeex = false;
+
+  public static LogLevel sLogLevel = LogLevel.DEBUG;
+  private static boolean isApkDebug = true;
+  public static boolean isPerf = false;
+  private static boolean sDebugFlagInit = false;
+
+  private static boolean openDebugLog = true;
+
+  private static String sGlobalFontFamily;
+
+  public static final String CORE_SO_NAME = "weexcore";
+  public static final String CORE_JSS_SO_NAME = "weexjss";
+  public static final String CORE_JSB_SO_NAME = "weexjsb";
+  public static final String CORE_JST_SO_NAME = "weexjst";
+
+  @RestrictTo(Scope.LIBRARY)
+  public static String CORE_JSC_SO_NAME = BuildConfig.JSInterpolatorName;
+  public static  String CORE_JSS_SO_PATH = null;
+
+  private static String CORE_JSS_ICU_PATH = null;
+
+  private static String CORE_JSC_SO_PATH = null;
+
+  public static String CORE_JSB_SO_PATH = null;
+
+  private static String COPY_SO_DES_DIR = null;
+
+  private static String LIB_LD_PATH = null;
+
+  private static Map<String, String> options = new ConcurrentHashMap<>();
+  static {
+    options.put(WXConfig.os, OS);
+    options.put(WXConfig.osName, OS);
+  }
+
+
+  public static synchronized WXDefaultSettings getWXDefaultSettings() {
+    if (mWXDefaultSettings == null && getApplication() != null) {
+      mWXDefaultSettings = new WXDefaultSettings(getApplication());
+    }
+    return mWXDefaultSettings;
+  }
+
+  public static synchronized String getDefaultSettingValue(String key, String defaultValue) {
+    WXDefaultSettings wxDefaultSettings = getWXDefaultSettings();
+    if (wxDefaultSettings == null || TextUtils.isEmpty(key)) {
+      return defaultValue;
+    }
+    return wxDefaultSettings.getValue(key, defaultValue);
+  }
+
+  public static synchronized void writeDefaultSettingsValue(String key, String value) {
+    WXDefaultSettings wxDefaultSettings = getWXDefaultSettings();
+    if (wxDefaultSettings == null
+            || TextUtils.isEmpty(key)
+            || TextUtils.isEmpty(value)) {
+      return;
+    }
+    wxDefaultSettings.saveValue(key, value);
+  }
+
+  private static WXDefaultSettings mWXDefaultSettings;
+
+  /**
+   * dynamic
+   */
+  public static boolean sDynamicMode = false;
+  public static String sDynamicUrl = "";
+
+  /**
+   * Fetch system information.
+   * @return map contains system information.
+   */
+  public static Map<String, String> getConfig() {
+    Map<String, String> configs = new HashMap<>();
+    configs.put(WXConfig.os, OS);
+    configs.put(WXConfig.appVersion, getAppVersionName());
+    configs.put(WXConfig.cacheDir, getAppCacheFile());
+    configs.put(WXConfig.devId, DEV_Id);
+    configs.put(WXConfig.sysVersion, SYS_VERSION);
+    configs.put(WXConfig.sysModel, SYS_MODEL);
+    configs.put(WXConfig.weexVersion, String.valueOf(WXSDK_VERSION));
+
+    try {
+      configs.put(WXConfig.layoutDirection, isLayoutDirectionRTL() ? "rtl" : "ltr");
+    } catch (Exception e) {
+      configs.put(WXConfig.layoutDirection, "ltr");
+    }
+
+    try {
+      if (isApkDebugable()) {
+        addCustomOptions(WXConfig.debugMode, "true");
+      }
+      addCustomOptions(WXConfig.scale, Float.toString(sApplication.getResources().getDisplayMetrics().density));
+      addCustomOptions(WXConfig.androidStatusBarHeight, Float.toString(WXViewUtils.getStatusBarHeight(sApplication)));
+    }catch (NullPointerException e){
+      //There is little chance of NullPointerException as sApplication may be null.
+      WXLogUtils.e("WXEnvironment scale Exception: ", e);
+    }
+    configs.putAll(getCustomOptions());
+    if(configs.get(WXConfig.appName)==null && sApplication!=null){
+      configs.put(WXConfig.appName, sApplication.getPackageName());
+    }
+    return configs;
+  }
+
+  /**
+   * Get the version of the current app.
+   */
+  public static String getAppVersionName() {
+    String versionName = "";
+    PackageManager manager;
+    PackageInfo info = null;
+    try {
+      manager = sApplication.getPackageManager();
+      info = manager.getPackageInfo(sApplication.getPackageName(), 0);
+      versionName = info.versionName;
+    } catch (Exception e) {
+      WXLogUtils.e("WXEnvironment getAppVersionName Exception: ", e);
+    }
+    return versionName;
+  }
+
+  /**
+   *
+   * @return string cache file
+   */
+  private static String getAppCacheFile() {
+    String cache = "";
+    try {
+      cache = sApplication.getApplicationContext().getCacheDir().getPath();
+    } catch (Exception e) {
+      WXLogUtils.e("WXEnvironment getAppCacheFile Exception: ", e);
+    }
+    return cache;
+  }
+
+
+  /**
+   * Use {@link #addCustomOptions(String, String)} to add custom options.
+   * Use {@link #getCustomOptions(String)} to get custom options
+   * @return
+   */
+  @Deprecated
+  public static Map<String, String> getCustomOptions() {
+    return options;
+  }
+
+  public static void addCustomOptions(String key, String value) {
+    options.put(key, value);
+  }
+
+  public static String getCustomOptions(String key){
+    return options.get(key);
+  }
+
+
+  @SuppressLint("SdCardPath")
+  public static String copySoDesDir() {
+    try {
+      if (TextUtils.isEmpty(COPY_SO_DES_DIR)) {
+        if (sApplication == null) {
+          WXLogUtils.e("sApplication is null, so copy path will be null");
+          return null;
+        }
+
+        String dirName = "/cache/weex/libs";
+        File desDir = null;
+        String cachePath = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
+
+        if (TextUtils.isEmpty(cachePath)) {
+          desDir = new File(cachePath, dirName);
+        } else {
+          String pkgName = sApplication.getPackageName();
+          String toPath = "/data/data/" + pkgName + dirName;
+          desDir = new File(toPath);
+        }
+
+        if (!desDir.exists()) {
+          desDir.mkdirs();
+        }
+        COPY_SO_DES_DIR = desDir.getAbsolutePath();
+      }
+    } catch (Throwable e) {
+      WXLogUtils.e(WXLogUtils.getStackTrace(e));
+    }
+    return COPY_SO_DES_DIR;
+
+  }
+
+  @Deprecated
+  /**
+   * Use {@link #isHardwareSupport()} if you want to see whether current hardware support Weex.
+   */
+  public static boolean isSupport() {
+    boolean isInitialized = WXSDKEngine.isInitialized();
+    if(!isInitialized){
+      WXLogUtils.e("WXSDKEngine.isInitialized():" + isInitialized);
+    }
+    return isHardwareSupport() && isInitialized;
+  }
+
+  public static boolean isLayoutDirectionRTL() {
+    // support RTL
+    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+      return sApplication.getApplicationContext().getResources().getBoolean(R.bool.weex_is_right_to_left);
+    }
+    return false;
+  }
+  /**
+   * Tell whether Weex can run on current hardware.
+   * @return true if weex can run on current hardware, otherwise false.
+   * Weex has removed the restrictions on the tablet, please use {@link #isCPUSupport()}
+   */
+  @Deprecated
+  public static boolean isHardwareSupport() {
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("isTableDevice:" + WXUtils.isTabletDevice());
+    }
+    return isCPUSupport();
+  }
+
+  /**
+   * Determine whether Weex supports the current CPU architecture
+   * @return true when support
+   */
+  public static boolean isCPUSupport(){
+    boolean excludeX86 = "true".equals(getCustomOptions().get(SETTING_EXCLUDE_X86SUPPORT));
+    boolean isX86AndExcluded = WXSoInstallMgrSdk.isX86() && excludeX86;
+    boolean isCPUSupport = WXSoInstallMgrSdk.isCPUSupport() && !isX86AndExcluded;
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("WXEnvironment.sSupport:" + isCPUSupport
+              + "isX86AndExclueded: "+ isX86AndExcluded);
+    }
+    return isCPUSupport;
+  }
+
+  public static boolean isApkDebugable() {
+    return isApkDebugable(sApplication);
+  }
+
+  public static boolean isApkDebugable(Application application) {
+    if (application == null) {
+      return false;
+    }
+
+    if (isPerf) {
+      return false;
+    }
+
+    if (sDebugFlagInit){
+      return isApkDebug;
+    }
+    try {
+      String debugModeConfig = getCustomOptions().get(WXConfig.debugMode);
+      if (TextUtils.isEmpty(debugModeConfig)){
+        ApplicationInfo info = application.getApplicationInfo();
+        isApkDebug = (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+      }else {
+        isApkDebug = Boolean.valueOf(debugModeConfig);
+      }
+    } catch (Exception e) {
+      /**
+       * Don't call WXLogUtils.e here,will cause stackoverflow
+       */
+      e.printStackTrace();
+      isApkDebug = false;
+    }
+    sDebugFlagInit = true;
+    return isApkDebug;
+  }
+
+  public static boolean isPerf() {
+    return isPerf;
+  }
+
+  @SuppressLint("HardwareIds")
+  private static String getDevId() {
+    String ret = "";
+    if(sApplication != null){
+      try{
+        ret = ((TelephonyManager) sApplication
+            .getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
+      }catch (SecurityException | NullPointerException e){
+        WXLogUtils.e(WXLogUtils.getStackTrace(e));
+      }
+    }
+    return ret;
+  }
+
+  public static Application getApplication() {
+    return sApplication;
+  }
+
+  public void initMetrics() {
+    if (sApplication == null) {
+      return;
+    }
+  }
+
+  public static String getDiskCacheDir(Context context) {
+    if (context == null) {
+      return null;
+    }
+    String cachePath = null;
+    try {
+      if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
+              || !Environment.isExternalStorageRemovable()) {
+        cachePath = context.getExternalCacheDir().getPath();
+      } else {
+        cachePath = context.getCacheDir().getPath();
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return cachePath;
+  }
+
+  public static String getFilesDir(Context context) {
+    if (context == null) {
+      return "";
+    }
+    File filesDir = context.getFilesDir();
+    String path = "";
+    if (filesDir != null) {
+      path = filesDir.getPath();
+    } else {
+      path = WXEnvironment.getApplication().getApplicationInfo().dataDir;
+      path += File.separator;
+      path += "files";
+    }
+
+    return path;
+  }
+
+  public static String getCrashFilePath(Context context) {
+    if (context == null) {
+        return "";
+    }
+
+    File dir = context.getDir("crash", Context.MODE_PRIVATE);
+    if (dir == null)
+        return "";
+
+    String crashDir = dir.getAbsolutePath();
+
+    return crashDir;
+  }
+
+  public static String getGlobalFontFamilyName() {
+    return sGlobalFontFamily;
+  }
+
+  public static void setGlobalFontFamily(String fontFamilyName, Typeface typeface) {
+    WXLogUtils.d("GlobalFontFamily", "Set global font family: " + fontFamilyName);
+    sGlobalFontFamily = fontFamilyName;
+    if (!TextUtils.isEmpty(fontFamilyName)) {
+      if (typeface == null) {
+        TypefaceUtil.removeFontDO(fontFamilyName);
+      } else {
+        FontDO nativeFontDO = new FontDO(fontFamilyName, typeface);
+        TypefaceUtil.putFontDO(nativeFontDO);
+        WXLogUtils.d("TypefaceUtil", "Add new font: " + fontFamilyName);
+      }
+    }
+  }
+
+  public static boolean isOpenDebugLog() {
+    return openDebugLog;
+  }
+
+  public static void setOpenDebugLog(boolean openDebugLog) {
+    WXEnvironment.openDebugLog = openDebugLog;
+  }
+
+  public static void  setApkDebugable(boolean debugable){
+    isApkDebug  = debugable;
+    if(!isApkDebug){
+      openDebugLog = false;
+    }
+  }
+
+  public static String getCacheDir() {
+    final Application application = getApplication();
+    if (application == null || application.getApplicationContext() == null)
+      return null;
+    return application.getApplicationContext().getCacheDir().getPath();
+  }
+
+  public static boolean extractSo() {
+    File sourceFile = new File(getApplication().getApplicationContext().getApplicationInfo().sourceDir);
+    final String soDesPath = copySoDesDir();
+    if (sourceFile.exists() && !TextUtils.isEmpty(soDesPath)) {
+      try {
+        WXFileUtils.extractSo(sourceFile.getAbsolutePath(), soDesPath);
+      } catch (IOException e) {
+        WXLogUtils.e("extractSo error " + e.getMessage());
+//        e.printStackTrace();
+        return false;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  private static String findIcuPath() {
+    File file = new File("/proc/self/maps");
+    BufferedReader reader = null;
+    try {
+      reader = new BufferedReader(new FileReader(file));
+      String tempString = null;
+      while ((tempString = reader.readLine()) != null) {
+        if (tempString.contains("icudt")) {
+
+          int i = tempString.indexOf('/');
+
+          String substring = tempString.substring(i);
+          return substring.trim();
+        }
+      }
+      reader.close();
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      if (reader != null) {
+        try {
+          reader.close();
+        } catch (IOException e1) {
+        }
+      }
+    }
+
+    return null;
+  }
+
+
+  public static String findSoPath(String libName) {
+    String soPath = ((PathClassLoader) (WXEnvironment.class.getClassLoader())).findLibrary(libName);
+    if (!TextUtils.isEmpty(soPath)) {
+      File soFile = new File(soPath);
+      if (soFile.exists()) {
+        WXLogUtils.e(libName + "'s Path is" + soPath);
+        return soFile.getAbsolutePath();
+      } else {
+        WXLogUtils.e(libName + "'s Path is " + soPath + " but file does not exist");
+      }
+    }
+
+    String realName = "lib" + libName + ".so";
+    String cacheDir = getCacheDir();
+    if (TextUtils.isEmpty(cacheDir)) {
+      WXLogUtils.e("cache dir is null");
+      return "";
+    }
+
+
+    if (cacheDir.indexOf("/cache") > 0) {
+      soPath = new File(cacheDir.replace("/cache", "/lib"), realName).getAbsolutePath();
+    }
+
+
+    final File soFile = new File(soPath);
+    if (soFile.exists()) {
+      WXLogUtils.e(libName + "use lib so");
+      return soPath;
+    } else {
+      //unzip from apk file
+      final boolean success = extractSo();
+      if (success) {
+        return new File(getCacheDir(), realName).getAbsolutePath();
+      }
+    }
+    return soPath;
+  }
+
+  public static String getLibJScRealPath() {
+    if(TextUtils.isEmpty(CORE_JSC_SO_PATH)) {
+      CORE_JSC_SO_PATH = findSoPath(CORE_JSC_SO_NAME);
+      WXLogUtils.e("findLibJscRealPath " + CORE_JSC_SO_PATH);
+    }
+    return CORE_JSC_SO_PATH;
+  }
+
+  public static String getLibJssRealPath() {
+    if(TextUtils.isEmpty(CORE_JSS_SO_PATH)) {
+      CORE_JSS_SO_PATH = findSoPath(CORE_JSS_SO_NAME);
+      WXLogUtils.d("test-> findLibJssRealPath " + CORE_JSS_SO_PATH);
+    }
+
+    return CORE_JSS_SO_PATH;
+  }
+
+  public static String getLibJssIcuPath() {
+    if(TextUtils.isEmpty(CORE_JSS_ICU_PATH)){
+      CORE_JSS_ICU_PATH = findIcuPath();
+    }
+
+    return CORE_JSS_ICU_PATH;
+  }
+
+  public static String getLibLdPath() {
+    if (TextUtils.isEmpty(LIB_LD_PATH)) {
+      ClassLoader classLoader = WXEnvironment.class.getClassLoader();
+      try {
+        Method getLdLibraryPath = classLoader.getClass().getMethod("getLdLibraryPath", new Class[0]);
+        LIB_LD_PATH = (String) getLdLibraryPath.invoke(classLoader, new Object[0]);
+      } catch (IllegalAccessException e) {
+        e.printStackTrace();
+      } catch (InvocationTargetException e) {
+        e.printStackTrace();
+      } catch (NoSuchMethodException e) {
+        e.printStackTrace();
+      }
+    }
+
+    if(TextUtils.isEmpty(LIB_LD_PATH)) {
+      try {
+        String property = System.getProperty("java.library.path");
+        String libJScRealPath = getLibJScRealPath();
+        if(!TextUtils.isEmpty(libJScRealPath)) {
+          LIB_LD_PATH = new File(libJScRealPath).getParent() + ":" + property;
+        }
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+
+    WXLogUtils.d("getLibLdPath is " + LIB_LD_PATH);
+    return LIB_LD_PATH;
+  }
+
+  public static class WXDefaultSettings {
+    private String configName = "weex_default_settings";
+    private SharedPreferences sharedPreferences = null;
+    public WXDefaultSettings(Application application) {
+      if(application != null) {
+        sharedPreferences = application.getSharedPreferences(configName, MODE_PRIVATE);
+      }
+    }
+
+    public synchronized String getValue(String key, String defaultValue) {
+      if(sharedPreferences == null || TextUtils.isEmpty(key)) {
+        WXLogUtils.i("get default settings " + key + " return default value :" + defaultValue);
+        return defaultValue;
+      }
+
+      String result = sharedPreferences.getString(key, defaultValue);
+      WXLogUtils.i("get default settings " + key + " : " + result);
+      return result;
+    }
+
+    public synchronized void saveValue(String key, String value) {
+      if (sharedPreferences == null
+              || TextUtils.isEmpty(key)
+              || TextUtils.isEmpty(value)) {
+        return;
+      }
+      WXLogUtils.i("save default settings " + key + ":" + value);
+      SharedPreferences.Editor editor = sharedPreferences.edit();
+      editor.putString(key, value);
+      editor.apply();
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/WXGlobalEventModule.java b/android/sdk/src/main/java/org/apache/weex/WXGlobalEventModule.java
new file mode 100644
index 0000000..9ad32e1
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WXGlobalEventModule.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.WXModule;
+
+import java.util.Map;
+
+/**
+ * Created by lixinke on 16/8/25.
+ */
+public class WXGlobalEventModule extends WXModule {
+
+
+  @JSMethod
+  public void addEventListener(String eventName, String callback) {
+    mWXSDKInstance.addEventListener(eventName,callback);
+  }
+
+  public void removeEventListener(String eventName, String callback) {
+    mWXSDKInstance.removeEventListener(eventName,callback);
+  }
+
+  @JSMethod
+  public void removeEventListener(String eventName){
+    mWXSDKInstance.removeEventListener(eventName);
+  }
+
+
+  @Override
+  public void addEventListener(String eventName, String callback, Map<String, Object> options) {
+    super.addEventListener(eventName, callback, options);
+    addEventListener(eventName,callback);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/WXGlobalEventReceiver.java b/android/sdk/src/main/java/org/apache/weex/WXGlobalEventReceiver.java
new file mode 100644
index 0000000..75c1f85
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WXGlobalEventReceiver.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.HashMap;
+
+public class WXGlobalEventReceiver extends BroadcastReceiver {
+
+  public static final String EVENT_NAME = "eventName";
+  public static final String EVENT_PARAMS = "eventParams";
+  public static final String EVENT_ACTION = "wx_global_action";
+  public static final String EVENT_WX_INSTANCEID = "wx_instanceid";
+
+  private WXSDKInstance mWXSDKInstance;
+
+  public WXGlobalEventReceiver() {
+  }
+
+  public WXGlobalEventReceiver(WXSDKInstance instance) {
+    mWXSDKInstance = instance;
+  }
+
+  @Override
+  public void onReceive(Context context, Intent intent) {
+    String eventName = intent.getStringExtra(EVENT_NAME);
+    String params = intent.getStringExtra(EVENT_PARAMS);
+    HashMap<String, Object> maps = null;
+    try {
+      maps = com.alibaba.fastjson.JSON.parseObject(params, HashMap.class);
+      mWXSDKInstance.fireGlobalEventCallback(eventName, maps);
+    } catch (Exception e) {
+      WXLogUtils.e("global-receive",e);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/WXHttpListener.java b/android/sdk/src/main/java/org/apache/weex/WXHttpListener.java
new file mode 100644
index 0000000..234c3c4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WXHttpListener.java
@@ -0,0 +1,307 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXPerformance;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.common.WXResponse;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.tracing.WXTracing;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.tools.LogDetail;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.weex.adapter.IWXHttpAdapter.OnHttpListener;
+
+/**
+ * load bundle js listener
+ */
+public class WXHttpListener implements OnHttpListener {
+
+    private String pageName;
+    private Map<String, Object> options;
+    private String jsonInitData;
+    private WXRenderStrategy flag;
+    private WXSDKInstance instance;
+    private long startRequestTime;
+    private int traceId;
+    private WXPerformance mWXPerformance;
+    private WXInstanceApm mApmForInstance;
+    private IWXUserTrackAdapter mUserTrackAdapter;
+    public boolean isPreDownLoadMode = false;
+    private boolean isInstanceReady =false;
+    private boolean isResponseHasWait = false;
+    private WXResponse mResponse;
+    private LogDetail mLogDetail;
+
+    private String mBundleUrl;
+
+    public WXHttpListener(WXSDKInstance instance) {
+        if(instance != null) {
+            mLogDetail = instance.mTimeCalculator.createLogDetail("downloadBundleJS");
+        }
+        this.instance = instance;
+        this.traceId = WXTracing.nextId();
+        this.mWXPerformance = instance.getWXPerformance();
+        this.mApmForInstance = instance.getApmForInstance();
+        this.mUserTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
+        if (WXTracing.isAvailable()) {
+            WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
+            event.iid = instance.getInstanceId();
+            event.tname = "Network";
+            event.ph = "B";
+            event.traceId = traceId;
+            event.submit();
+        }
+    }
+
+    public WXHttpListener(WXSDKInstance instance, String bundleUrl) {
+        this(instance);
+        this.startRequestTime = System.currentTimeMillis();
+        this.mBundleUrl = bundleUrl;
+    }
+
+    public WXHttpListener(WXSDKInstance instance, String pageName, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag, long startRequestTime) {
+        this(instance);
+        this.pageName = pageName;
+        this.options = options;
+        this.jsonInitData = jsonInitData;
+        this.flag = flag;
+        this.startRequestTime = startRequestTime;
+        this.mBundleUrl = instance.getBundleUrl();
+    }
+
+    public void setSDKInstance(WXSDKInstance instance) {
+        this.instance = instance;
+    }
+
+    protected WXSDKInstance getInstance() {
+        return instance;
+    }
+
+    @Override
+    public void onHttpStart() {
+        if (this.instance != null
+                && this.instance.getWXStatisticsListener() != null) {
+            this.instance.getWXStatisticsListener().onHttpStart();
+            if(mLogDetail != null) {
+                mLogDetail.taskStart();
+            }
+        }
+    }
+
+    @Override
+    public void onHeadersReceived(int statusCode, Map<String,List<String>> headers) {
+        if (this.instance != null
+                && this.instance.getWXStatisticsListener() != null) {
+            this.instance.getWXStatisticsListener().onHeadersReceived();
+            this.instance.onHttpStart();
+        }
+        if(this.instance != null
+                && this.instance.responseHeaders != null
+                && headers != null){
+            this.instance.responseHeaders.putAll(headers);
+        }
+    }
+
+    @Override
+    public void onHttpUploadProgress(int uploadProgress) {
+
+    }
+
+    @Override
+    public void onHttpResponseProgress(int loadedLength) {
+        instance.getApmForInstance().extInfo.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadedLength);
+    }
+
+    @Override
+    public void onHttpFinish(WXResponse response) {
+        if(mLogDetail != null) {
+            mLogDetail.taskEnd();
+        }
+        if (this.instance != null
+                && this.instance.getWXStatisticsListener() != null) {
+            this.instance.getWXStatisticsListener().onHttpFinish();
+        }
+
+        if (WXTracing.isAvailable()) {
+            WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
+            event.traceId = traceId;
+            event.tname = "Network";
+            event.ph = "E";
+            event.extParams = new HashMap<>();
+            if (response != null && response.originalData != null) {
+                event.extParams.put("BundleSize", response.originalData.length);
+            }
+            event.submit();
+        }
+
+        mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime;
+        if(null!= response && response.extendParams!=null){
+            mApmForInstance.updateRecordInfo(response.extendParams);
+            Object actualNetworkTime=response.extendParams.get("actualNetworkTime");
+            mWXPerformance.actualNetworkTime=actualNetworkTime instanceof Long?(long)actualNetworkTime:0;
+
+            Object pureNetworkTime=response.extendParams.get("pureNetworkTime");
+            mWXPerformance.pureNetworkTime=pureNetworkTime instanceof Long?(long)pureNetworkTime:0;
+
+            Object connectionType=response.extendParams.get("connectionType");
+            mWXPerformance.connectionType=connectionType instanceof String?(String)connectionType:"";
+
+            Object packageSpendTime=response.extendParams.get("packageSpendTime");
+            mWXPerformance.packageSpendTime=packageSpendTime instanceof Long ?(long)packageSpendTime:0;
+
+            Object syncTaskTime=response.extendParams.get("syncTaskTime");
+            mWXPerformance.syncTaskTime=syncTaskTime instanceof Long ?(long)syncTaskTime:0;
+
+            Object requestType=response.extendParams.get("requestType");
+            mWXPerformance.requestType=requestType instanceof String?(String)requestType:"none";
+
+            Object cacheType = response.extendParams.get(WXPerformance.Dimension.cacheType.toString());
+            if(cacheType instanceof String){
+                mWXPerformance.cacheType = (String) cacheType;
+            }
+
+            Object zCacheInfo = response.extendParams.get("zCacheInfo");
+            mWXPerformance.zCacheInfo = zCacheInfo instanceof String?(String)zCacheInfo:"";
+
+            if(isNet(mWXPerformance.requestType) && mUserTrackAdapter!=null){
+                WXPerformance performance=new WXPerformance(instance.getInstanceId());
+                if(!TextUtils.isEmpty(mBundleUrl)){
+                    try {
+                        performance.args= Uri.parse(mBundleUrl).buildUpon().clearQuery().toString();
+                    } catch (Exception e) {
+                        performance.args=pageName;
+                    }
+                }
+                if(!"200".equals(response.statusCode)){
+                    performance.errCode= WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
+                    performance.appendErrMsg(response.errorCode);
+                    performance.appendErrMsg("|");
+                    performance.appendErrMsg(response.errorMsg);
+
+                }else if("200".equals(response.statusCode) && (response.originalData==null || response.originalData.length<=0)){
+                    performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
+                    performance.appendErrMsg(response.statusCode);
+                    performance.appendErrMsg("|template is null!");
+                }else {
+                    performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode();
+                }
+
+                if (mUserTrackAdapter != null) {
+                    mUserTrackAdapter.commit(instance.getContext(), null, IWXUserTrackAdapter.JS_DOWNLOAD, performance, null);
+                }
+            }
+        }
+
+        if (isPreDownLoadMode){
+            if (isInstanceReady){
+                WXLogUtils.d("test->", "DownLoad didHttpFinish on http" );
+                didHttpFinish(response);
+            }else {
+                WXLogUtils.d("test->", "DownLoad end before activity created" );
+                mResponse = response;
+                isResponseHasWait = true;
+            }
+        }else {
+            didHttpFinish(response);
+        }
+
+    }
+
+    public void onInstanceReady(){
+        if (!isPreDownLoadMode){
+            return;
+        }
+        this.isInstanceReady = true;
+        if (isResponseHasWait){
+            WXLogUtils.d("test->", "preDownLoad didHttpFinish on ready" );
+            this.didHttpFinish(mResponse);
+        }
+
+    }
+
+    private void didHttpFinish(WXResponse response){
+        String wxErrorCode = WXInstanceApm.VALUE_ERROR_CODE_DEFAULT;
+        if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) {
+            mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END);
+            onSuccess(response);
+
+            // check content-type
+        } else if (TextUtils.equals(WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode(),
+                response.statusCode)) {
+            WXLogUtils.e("user intercept: WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR");
+            wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode();
+            instance.onRenderError(wxErrorCode,
+                    "|response.errorMsg==" + response.errorMsg +
+                            "|instance bundleUrl = \n" + instance.getBundleUrl() +
+                            "|instance requestUrl = \n" + Uri.decode(WXSDKInstance.requestUrl)
+            );
+            onFail(response);
+
+            // check content-length
+        } else if (response!=null && response.originalData!=null && TextUtils.equals("-206", response.statusCode)) {
+            WXLogUtils.e("user intercept: WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED");
+            wxErrorCode =  WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode();
+            instance.onRenderError(wxErrorCode ,
+                    WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode() +
+                            "|response.errorMsg==" + response.errorMsg
+            );
+            onFail(response);
+        }
+        else {
+            wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode();
+            instance.onRenderError(wxErrorCode,
+                    response.errorMsg);
+            onFail(response);
+        }
+        if (!WXInstanceApm.VALUE_ERROR_CODE_DEFAULT.equals(wxErrorCode)){
+            mApmForInstance.addProperty(WXInstanceApm.KEY_PROPERTIES_ERROR_CODE,wxErrorCode);
+        }
+    }
+
+    private boolean isNet(String requestType){
+
+        return "network".equals(requestType) || "2g".equals(requestType) || "3g".equals(requestType)
+                || "4g".equals(requestType) || "wifi".equals(requestType) || "other".equals(requestType)
+                || "unknown".equals(requestType);
+    }
+
+    public void onSuccess(WXResponse response) {
+        if (flag==WXRenderStrategy.DATA_RENDER_BINARY){
+            instance.render(pageName, response.originalData, options, jsonInitData);
+        }else {
+            String template = new String(response.originalData);
+            instance.render(pageName, template, options, jsonInitData, flag);
+        }
+    }
+
+    public void onFail(WXResponse response) {
+
+    }
+}
+
+
diff --git a/android/sdk/src/main/java/org/apache/weex/WXSDKEngine.java b/android/sdk/src/main/java/org/apache/weex/WXSDKEngine.java
new file mode 100644
index 0000000..ed1cda6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WXSDKEngine.java
@@ -0,0 +1,601 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.support.v4.content.LocalBroadcastManager;
+import android.text.TextUtils;
+import org.apache.weex.adapter.IDrawableLoader;
+import org.apache.weex.adapter.IWXHttpAdapter;
+import org.apache.weex.adapter.IWXImgLoaderAdapter;
+import org.apache.weex.adapter.IWXJSExceptionAdapter;
+import org.apache.weex.adapter.IWXJsFileLoaderAdapter;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.appfram.clipboard.WXClipboardModule;
+import org.apache.weex.appfram.navigator.IActivityNavBarSetter;
+import org.apache.weex.appfram.navigator.INavigator;
+import org.apache.weex.appfram.navigator.WXNavigatorModule;
+import org.apache.weex.appfram.pickers.WXPickersModule;
+import org.apache.weex.appfram.storage.IWXStorageAdapter;
+import org.apache.weex.appfram.storage.WXStorageModule;
+import org.apache.weex.appfram.websocket.WebSocketModule;
+import org.apache.weex.bridge.ModuleFactory;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.bridge.WXModuleManager;
+import org.apache.weex.bridge.WXServiceManager;
+import org.apache.weex.common.Destroyable;
+import org.apache.weex.common.TypeModuleFactory;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXException;
+import org.apache.weex.common.WXInstanceWrap;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.http.WXStreamModule;
+import org.apache.weex.performance.WXStateRecord;
+import org.apache.weex.ui.ExternalLoaderComponentHolder;
+import org.apache.weex.ui.IExternalComponentGetter;
+import org.apache.weex.ui.IExternalModuleGetter;
+import org.apache.weex.ui.IFComponentHolder;
+import org.apache.weex.ui.SimpleComponentHolder;
+import org.apache.weex.ui.WXComponentRegistry;
+import org.apache.weex.ui.animation.WXAnimationModule;
+import org.apache.weex.ui.component.Textarea;
+import org.apache.weex.ui.component.WXA;
+import org.apache.weex.ui.component.WXBasicComponentType;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXDiv;
+import org.apache.weex.ui.component.WXEmbed;
+import org.apache.weex.ui.component.WXHeader;
+import org.apache.weex.ui.component.WXImage;
+import org.apache.weex.ui.component.WXIndicator;
+import org.apache.weex.ui.component.WXInput;
+import org.apache.weex.ui.component.WXLoading;
+import org.apache.weex.ui.component.WXLoadingIndicator;
+import org.apache.weex.ui.component.WXRefresh;
+import org.apache.weex.ui.component.WXScroller;
+import org.apache.weex.ui.component.WXSlider;
+import org.apache.weex.ui.component.WXSliderNeighbor;
+import org.apache.weex.ui.component.WXSwitch;
+import org.apache.weex.ui.component.WXText;
+import org.apache.weex.ui.component.WXVideo;
+import org.apache.weex.ui.component.WXWeb;
+import org.apache.weex.ui.component.list.HorizontalListComponent;
+import org.apache.weex.ui.component.list.SimpleListComponent;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.component.list.WXListComponent;
+import org.apache.weex.ui.component.list.template.WXRecyclerTemplateList;
+import org.apache.weex.ui.component.richtext.WXRichText;
+import org.apache.weex.ui.config.AutoScanConfigRegister;
+import org.apache.weex.ui.module.WXDeviceInfoModule;
+import org.apache.weex.ui.module.ConsoleLogModule;
+import org.apache.weex.ui.module.WXLocaleModule;
+import org.apache.weex.ui.module.WXMetaModule;
+import org.apache.weex.ui.module.WXModalUIModule;
+import org.apache.weex.ui.module.WXTimerModule;
+import org.apache.weex.ui.module.WXWebViewModule;
+import org.apache.weex.utils.LogLevel;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXSoInstallMgrSdk;
+import org.apache.weex.utils.batch.BatchOperationHelper;
+import org.apache.weex.utils.cache.RegisterCache;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+public class WXSDKEngine implements Serializable {
+
+  public static final String JS_FRAMEWORK_RELOAD="js_framework_reload";
+  private static final String V8_SO_NAME = WXEnvironment.CORE_SO_NAME;
+  private volatile static boolean mIsInit = false;
+  private volatile static boolean mIsSoInit = false;
+  private static final Object mLock = new Object();
+  private static final String TAG = "WXSDKEngine";
+
+  /**
+   * Deprecated. Use {@link #initialize(Application, InitConfig)} instead.
+   */
+  @Deprecated
+  public static void init(Application application) {
+    init(application, null);
+  }
+
+  /**
+   * Deprecated. Use {@link #initialize(Application, InitConfig)} instead.
+   */
+  @Deprecated
+  public static void init(Application application, IWXUserTrackAdapter utAdapter) {
+    init(application, utAdapter, null);
+  }
+
+  /**
+   * Deprecated. Use {@link #initialize(Application, InitConfig)} instead.
+   */
+  @Deprecated
+  public static void init(Application application, IWXUserTrackAdapter utAdapter, String framework) {
+    initialize(application,
+            new InitConfig.Builder()
+                    .setUtAdapter(utAdapter)
+                    .build()
+    );
+  }
+
+
+  public static boolean isInitialized(){
+    synchronized(mLock) {
+
+      return mIsInit && WXEnvironment.JsFrameworkInit;
+    }
+  }
+
+  public static boolean isSoInitialized(){
+    synchronized(mLock) {
+      return mIsSoInit;
+    }
+  }
+
+  /**
+   *
+   * @param application
+   * @param config initial configurations or null
+   */
+  public static void initialize(Application application,InitConfig config){
+    synchronized (mLock) {
+      if (mIsInit) {
+        return;
+      }
+      long start = System.currentTimeMillis();
+      WXEnvironment.sSDKInitStart = start;
+      if(WXEnvironment.isApkDebugable(application)){
+        WXEnvironment.sLogLevel = LogLevel.DEBUG;
+      }else{
+        WXEnvironment.sLogLevel = LogLevel.WARN;
+      }
+      doInitInternal(application,config);
+      registerApplicationOptions(application);
+      WXEnvironment.sSDKInitInvokeTime = System.currentTimeMillis()-start;
+      WXLogUtils.renderPerformanceLog("SDKInitInvokeTime", WXEnvironment.sSDKInitInvokeTime);
+      mIsInit = true;
+    }
+  }
+
+  private static void registerApplicationOptions(final Application application) {
+
+    if (application == null) {
+      WXLogUtils.e(TAG, "RegisterApplicationOptions application is null");
+      return;
+    }
+
+    Resources resources = application.getResources();
+    registerCoreEnv("screen_width_pixels", String.valueOf(resources.getDisplayMetrics().widthPixels));
+    registerCoreEnv("screen_height_pixels", String.valueOf(resources.getDisplayMetrics().heightPixels));
+
+    int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
+    if (resourceId > 0) {
+      int statusBarHeight = resources.getDimensionPixelSize(resourceId);
+      registerCoreEnv("status_bar_height", String.valueOf(statusBarHeight));
+    }
+  }
+
+  private static void doInitInternal(final Application application,final InitConfig config){
+    WXEnvironment.sApplication = application;
+    if(application == null){
+      WXLogUtils.e(TAG, " doInitInternal application is null");
+      WXExceptionUtils.commitCriticalExceptionRT(null,
+              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
+              "doInitInternal",
+              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "WXEnvironment sApplication is null",
+              null);
+    }
+    WXEnvironment.JsFrameworkInit = false;
+
+    WXBridgeManager.getInstance().postWithName(new Runnable() {
+      @Override
+      public void run() {
+        long start = System.currentTimeMillis();
+        WXSDKManager sm = WXSDKManager.getInstance();
+        sm.onSDKEngineInitialize();
+        if(config != null ) {
+          sm.setInitConfig(config);
+        }
+        WXSoInstallMgrSdk.init(application,
+                sm.getIWXSoLoaderAdapter(),
+                sm.getWXStatisticsListener());
+        final IWXUserTrackAdapter userTrackAdapter= config!=null?config.getUtAdapter():null;
+        final int version = 1;
+        mIsSoInit = WXSoInstallMgrSdk.initSo(V8_SO_NAME, version, userTrackAdapter);
+        WXSoInstallMgrSdk.copyJssRuntimeSo();
+        if(config!=null) {
+          for (String libraryName : config.getNativeLibraryList()) {
+            WXSoInstallMgrSdk.initSo(libraryName, version, userTrackAdapter);
+          }
+        }
+        if (!mIsSoInit) {
+          WXExceptionUtils.commitCriticalExceptionRT(null,
+                  WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
+                  "doInitInternal",
+                  WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "isSoInit false",
+                  null);
+          return;
+        }
+        sm.initScriptsFramework(config!=null?config.getFramework():null);
+
+        WXEnvironment.sSDKInitExecuteTime = System.currentTimeMillis() - start;
+        WXLogUtils.renderPerformanceLog("SDKInitExecuteTime", WXEnvironment.sSDKInitExecuteTime);
+      }
+    },null,"doInitWeexSdkInternal");
+    WXStateRecord.getInstance().startJSThreadWatchDog();
+    register();
+  }
+
+  @Deprecated
+  public static void init(Application application, String framework, IWXUserTrackAdapter utAdapter, IWXImgLoaderAdapter imgLoaderAdapter, IWXHttpAdapter httpAdapter) {
+    initialize(application,
+            new InitConfig.Builder()
+                    .setUtAdapter(utAdapter)
+                    .setHttpAdapter(httpAdapter)
+                    .setImgAdapter(imgLoaderAdapter)
+                    .build()
+    );
+  }
+
+  public static void setJSExcetptionAdapter(IWXJSExceptionAdapter excetptionAdapter){
+    WXSDKManager.getInstance().setIWXJSExceptionAdapter(excetptionAdapter);
+  }
+
+  private static void register() {
+    BatchOperationHelper batchHelper = new BatchOperationHelper(WXBridgeManager.getInstance());
+    try {
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXText.class,
+                      new WXText.Creator()
+              ),
+              false,
+              WXBasicComponentType.TEXT
+      );
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXDiv.class,
+                      new WXDiv.Ceator()
+              ),
+              false,
+              WXBasicComponentType.CONTAINER,
+              WXBasicComponentType.DIV,
+              WXBasicComponentType.HEADER,
+              WXBasicComponentType.FOOTER
+      );
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXImage.class,
+                      new WXImage.Creator()
+              ),
+              false,
+              WXBasicComponentType.IMAGE,
+              WXBasicComponentType.IMG
+      );
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXScroller.class,
+                      new WXScroller.Creator()
+              ),
+              false,
+              WXBasicComponentType.SCROLLER
+      );
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXSlider.class,
+                      new WXSlider.Creator()
+              ),
+              true,
+              WXBasicComponentType.SLIDER,
+              WXBasicComponentType.CYCLE_SLIDER
+      );
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXSliderNeighbor.class,
+                      new WXSliderNeighbor.Creator()
+              ),
+              true,
+              WXBasicComponentType.SLIDER_NEIGHBOR
+      );
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXCell.class,
+                      new WXCell.Creator()
+              ),
+              true,
+              WXBasicComponentType.CELL);
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXListComponent.class,
+                      new WXListComponent.Creator()
+              ),
+              true,
+              WXBasicComponentType.LIST,
+              WXBasicComponentType.VLIST,
+              WXBasicComponentType.RECYCLER,
+              WXBasicComponentType.WATERFALL);
+
+      registerComponent(
+              new SimpleComponentHolder(
+                      WXRichText.class,
+                      new WXRichText.Creator()
+              ),
+              false,
+              WXBasicComponentType.RICHTEXT
+      );
+
+      String simpleList = "simplelist";
+      registerComponent(SimpleListComponent.class,false,simpleList);
+      registerComponent(WXRecyclerTemplateList.class, false,WXBasicComponentType.RECYCLE_LIST);
+      registerComponent(HorizontalListComponent.class,false,WXBasicComponentType.HLIST);
+      registerComponent(WXBasicComponentType.CELL_SLOT, WXCell.class, true);
+      registerComponent(WXBasicComponentType.INDICATOR, WXIndicator.class, true);
+      registerComponent(WXBasicComponentType.VIDEO, WXVideo.class, false);
+      registerComponent(WXBasicComponentType.INPUT, WXInput.class, false);
+      registerComponent(WXBasicComponentType.TEXTAREA, Textarea.class,false);
+      registerComponent(WXBasicComponentType.SWITCH, WXSwitch.class, false);
+      registerComponent(WXBasicComponentType.A, WXA.class, false);
+      registerComponent(WXBasicComponentType.EMBED, WXEmbed.class, true);
+      registerComponent(WXBasicComponentType.WEB, WXWeb.class);
+      registerComponent(WXBasicComponentType.REFRESH, WXRefresh.class);
+      registerComponent(WXBasicComponentType.LOADING, WXLoading.class);
+      registerComponent(WXBasicComponentType.LOADING_INDICATOR, WXLoadingIndicator.class);
+      registerComponent(WXBasicComponentType.HEADER, WXHeader.class);
+
+      registerModule("modal", WXModalUIModule.class);
+      registerModule("instanceWrap", WXInstanceWrap.class);
+      registerModule("animation", WXAnimationModule.class);
+      registerModule("webview", WXWebViewModule.class);
+      registerModule("navigator", WXNavigatorModule.class);
+      registerModule("stream", WXStreamModule.class);
+      registerModule("timer", WXTimerModule.class);
+      registerModule("storage", WXStorageModule.class);
+      registerModule("clipboard", WXClipboardModule.class);
+      registerModule("globalEvent",WXGlobalEventModule.class);
+      registerModule("picker", WXPickersModule.class);
+      registerModule("meta", WXMetaModule.class);
+      registerModule("webSocket", WebSocketModule.class);
+      registerModule("locale", WXLocaleModule.class);
+      registerModule("deviceInfo", WXDeviceInfoModule.class);
+      registerModule("sdk-console-log", ConsoleLogModule.class);
+    } catch (WXException e) {
+      WXLogUtils.e("[WXSDKEngine] register:", e);
+    }
+
+    if(RegisterCache.getInstance().enableAutoScan()) {
+      AutoScanConfigRegister.doScanConfig();
+    }
+
+    batchHelper.flush();
+  }
+
+  /**
+   *
+   * Register component. The registration is singleton in {@link WXSDKEngine} level
+   * @param type name of component. Same as type field in the JS.
+   * @param clazz the class of the {@link WXComponent} to be registered.
+   * @param appendTree true for appendTree flag
+   * @return true for registration success, false for otherwise.
+   * @throws WXException Throws exception if type conflicts.
+   */
+  public static boolean registerComponent(String type, Class<? extends WXComponent> clazz, boolean appendTree) throws WXException {
+    return registerComponent(clazz, appendTree,type);
+  }
+
+  public static boolean registerComponent(String type, IExternalComponentGetter componentGetter, boolean appendTree) throws WXException {
+    return registerComponent(new ExternalLoaderComponentHolder(type,componentGetter), appendTree,type);
+  }
+
+  /**
+   *
+   * Register component. The registration is singleton in {@link WXSDKEngine} level
+   * @param clazz the class of the {@link WXComponent} to be registered.
+   * @param appendTree true for appendTree flag
+   * @return true for registration success, false for otherwise.
+   * @param names names(alias) of component. Same as type field in the JS.
+   * @throws WXException Throws exception if type conflicts.
+   */
+  public static boolean registerComponent(Class<? extends WXComponent> clazz, boolean appendTree,String ... names) throws WXException {
+    if(clazz == null){
+      return false;
+    }
+    SimpleComponentHolder holder = new SimpleComponentHolder(clazz);
+    return registerComponent(holder,appendTree,names);
+  }
+
+
+  public static boolean registerComponent(IFComponentHolder holder, boolean appendTree, String ... names) throws WXException {
+    boolean result =  true;
+    try {
+      for (String name : names) {
+        Map<String, Object> componentInfo = new HashMap<>();
+        if (appendTree) {
+          componentInfo.put("append", "tree");
+        }
+        result = result && WXComponentRegistry.registerComponent(name, holder, componentInfo);
+      }
+      return result;
+    } catch (Throwable e) {
+      e.printStackTrace();
+      return result;
+    }
+  }
+
+  /**
+   * Register module. This is a wrapper method for
+   * {@link #registerModule(String, Class, boolean)}. The module register here only need to
+   * be singleton in {@link WXSDKInstance} level.
+   * @param moduleName  module name
+   * @param moduleClass module to be registered.
+   * @return true for registration success, false for otherwise.
+   * {@link WXModuleManager#registerModule(String, ModuleFactory, boolean)}
+   */
+  public static <T extends WXModule> boolean registerModule(String moduleName, Class<T> moduleClass,boolean global) throws WXException {
+    return moduleClass != null && registerModule(moduleName, new TypeModuleFactory<>(moduleClass), global);
+  }
+
+  /**
+   * Register module. This is a wrapper method for
+   * {@link #registerModule(String, Class, boolean)}. The module register here only need to
+   * be singleton in {@link WXSDKInstance} level.
+   * @param moduleName  module name
+   * @param factory module factory to be registered. You can override {@link DestroyableModuleFactory#buildInstance()} to customize module creation.
+   * @return true for registration success, false for otherwise.
+   * {@link WXModuleManager#registerModule(String, ModuleFactory, boolean)}
+   */
+  public static <T extends WXModule> boolean registerModuleWithFactory(String moduleName, DestroyableModuleFactory factory, boolean global) throws WXException {
+    return registerModule(moduleName, factory,global);
+  }
+
+
+  public static <T extends WXModule> boolean registerModuleWithFactory(String moduleName, IExternalModuleGetter factory, boolean global) throws WXException {
+    return registerModule(moduleName, factory.getExternalModuleClass(moduleName,WXEnvironment.getApplication()),global);
+  }
+
+  public static <T extends WXModule> boolean registerModule(String moduleName, ModuleFactory factory, boolean global) throws WXException {
+    return WXModuleManager.registerModule(moduleName, factory,global);
+  }
+
+  public static boolean registerModule(String moduleName, Class<? extends WXModule> moduleClass) throws WXException {
+    return registerModule(moduleName, moduleClass,false);
+  }
+
+  public static boolean registerService(String name, String serviceScript, Map<String, Object> options) {
+    return WXServiceManager.registerService(name, serviceScript, options);
+  }
+
+  public static boolean unRegisterService(String name) {
+    return WXServiceManager.unRegisterService(name);
+  }
+
+  /**
+   * module implement {@link Destroyable}
+   */
+  public static abstract class DestroyableModule extends WXModule implements Destroyable {}
+
+  public static  abstract  class DestroyableModuleFactory<T extends DestroyableModule> extends TypeModuleFactory<T> {
+    public DestroyableModuleFactory(Class<T> clz) {
+      super(clz);
+    }
+  }
+
+  public static void callback(String instanceId, String funcId, Map<String, Object> data) {
+    WXSDKManager.getInstance().callback(instanceId, funcId, data);
+  }
+
+  /**
+   * Model switch, only applicable for developer model
+   * @param debug
+   */
+  public static void restartBridge(boolean debug) {
+    WXEnvironment.sDebugMode = debug;
+    WXSDKManager.getInstance().restartBridge();
+  }
+
+  public static boolean registerComponent(String type, Class<? extends WXComponent> clazz) throws WXException {
+    return WXComponentRegistry.registerComponent(type, new SimpleComponentHolder(clazz),new HashMap<String, Object>());
+  }
+
+  public static boolean registerComponent(Map<String, Object> componentInfo, Class<? extends WXComponent> clazz) throws WXException {
+    if(componentInfo == null){
+      return false;
+    }
+    String type = (String)componentInfo.get("type");
+    if(TextUtils.isEmpty(type)){
+      return false;
+    }
+    return WXComponentRegistry.registerComponent(type,new SimpleComponentHolder(clazz), componentInfo);
+  }
+
+  public static void addCustomOptions(String key, String value) {
+    WXEnvironment.addCustomOptions(key, value);
+  }
+
+  public static IWXUserTrackAdapter getIWXUserTrackAdapter() {
+    return WXSDKManager.getInstance().getIWXUserTrackAdapter();
+  }
+
+  public static IWXImgLoaderAdapter getIWXImgLoaderAdapter() {
+    return WXSDKManager.getInstance().getIWXImgLoaderAdapter();
+  }
+
+  public static IDrawableLoader getDrawableLoader() {
+    return WXSDKManager.getInstance().getDrawableLoader();
+  }
+
+  public static IWXHttpAdapter getIWXHttpAdapter() {
+    return WXSDKManager.getInstance().getIWXHttpAdapter();
+  }
+
+  public static IWXStorageAdapter getIWXStorageAdapter() {
+    return WXSDKManager.getInstance().getIWXStorageAdapter();
+  }
+
+
+  public static IWXJsFileLoaderAdapter getIWXJsFileLoaderAdapter() {
+    return WXSDKManager.getInstance().getIWXJsFileLoaderAdapter();
+  }
+
+  public static IActivityNavBarSetter getActivityNavBarSetter() {
+    return WXSDKManager.getInstance().getActivityNavBarSetter();
+  }
+
+  public static INavigator getNavigator() {
+    return WXSDKManager.getInstance().getNavigator();
+  }
+
+  public static  void setNavigator(INavigator navigator) {
+    WXSDKManager.getInstance().setNavigator(navigator);
+  }
+
+  public static void setActivityNavBarSetter(IActivityNavBarSetter activityNavBarSetter) {
+    WXSDKManager.getInstance().setActivityNavBarSetter(activityNavBarSetter);
+  }
+
+  public static void reload(final Context context,String framework, boolean remoteDebug) {
+    WXEnvironment.sRemoteDebugMode = remoteDebug;
+    WXBridgeManager.getInstance().restart();
+    WXBridgeManager.getInstance().initScriptsFramework(framework);
+
+    WXServiceManager.reload();
+    WXModuleManager.reload();
+    WXComponentRegistry.reload();
+    WXSDKManager.getInstance().postOnUiThread(new Runnable() {
+      @Override
+      public void run() {
+        LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(JS_FRAMEWORK_RELOAD));
+      }
+    }, 0);
+  }
+  public static void reload(final Context context, boolean remoteDebug) {
+    reload(context,null,remoteDebug);
+  }
+
+  public static void reload() {
+    reload(WXEnvironment.getApplication(), WXEnvironment.sRemoteDebugMode);
+  }
+
+  public static void registerCoreEnv(String key, String value) {
+    WXBridgeManager.getInstance().registerCoreEnv(key, value);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/WXSDKInstance.java b/android/sdk/src/main/java/org/apache/weex/WXSDKInstance.java
new file mode 100644
index 0000000..0ea578c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WXSDKInstance.java
@@ -0,0 +1,2462 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import static org.apache.weex.http.WXHttpUtil.KEY_USER_AGENT;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.annotation.WorkerThread;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.adapter.IDrawableLoader;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.adapter.IWXHttpAdapter;
+import org.apache.weex.adapter.IWXImgLoaderAdapter;
+import org.apache.weex.adapter.IWXJscProcessManager;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.appfram.websocket.IWebSocketAdapter;
+import org.apache.weex.bridge.EventResult;
+import org.apache.weex.bridge.NativeInvokeHelper;
+import org.apache.weex.bridge.SimpleJSCallback;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.bridge.WXModuleManager;
+import org.apache.weex.bridge.WXParams;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.Destroyable;
+import org.apache.weex.common.OnWXScrollListener;
+import org.apache.weex.common.RenderTypes;
+import org.apache.weex.common.WXConfig;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.common.WXPerformance;
+import org.apache.weex.common.WXRefreshData;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.common.WXRequest;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.http.WXHttpUtil;
+import org.apache.weex.instance.InstanceOnFireEventInterceptor;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.performance.WXStateRecord;
+import org.apache.weex.performance.WhiteScreenUtils;
+import org.apache.weex.render.WXAbstractRenderContainer;
+import org.apache.weex.tracing.WXTracing;
+import org.apache.weex.ui.action.GraphicActionAddElement;
+import org.apache.weex.ui.component.NestedContainer;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXEmbed;
+import org.apache.weex.ui.flat.FlatGUIContext;
+import org.apache.weex.ui.view.WXScrollView;
+import org.apache.weex.utils.Trace;
+import org.apache.weex.utils.WXDeviceUtils;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXFileUtils;
+import org.apache.weex.utils.WXJsonUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXReflectionUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import org.apache.weex.utils.cache.RegisterCache;
+import org.apache.weex.utils.tools.LogDetail;
+import org.apache.weex.utils.tools.TimeCalculator;
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.weex.bridge.WXBridgeManager.BundType;
+
+
+/**
+ * Each instance of WXSDKInstance represents an running weex instance.
+ * It can be a pure weex view, or mixed with native view
+ */
+public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChangeListener {
+
+  private static  final  String SOURCE_TEMPLATE_BASE64_MD5 = "templateSourceBase64MD5";
+
+  /**
+   * Devtool protocol
+   */
+  public static String ACTION_DEBUG_INSTANCE_REFRESH = "DEBUG_INSTANCE_REFRESH";
+  public static String ACTION_INSTANCE_RELOAD = "INSTANCE_RELOAD";
+
+  //Performance
+  public boolean mEnd = false;
+  public boolean mHasCreateFinish = false;
+  public static final String BUNDLE_URL = "bundleUrl";
+  private IWXUserTrackAdapter mUserTrackAdapter;
+  private IWXRenderListener mRenderListener;
+  private IWXStatisticsListener mStatisticsListener;
+  /** package **/ Context mContext;
+  private final String mInstanceId;
+  private WXAbstractRenderContainer mRenderContainer;
+  private WXComponent mRootComp;
+  private boolean mRendered;
+  private WXRefreshData mLastRefreshData;
+  private NestedInstanceInterceptor mNestedInstanceInterceptor;
+  private String mBundleUrl = "";
+  public static String requestUrl = "requestUrl";
+  private boolean isDestroy=false;
+  private boolean hasException = false;
+  private boolean isRenderSuccess = false;
+  private boolean createInstanceHeartBeat = false;
+  private Map<String,Serializable> mUserTrackParams;
+  private NativeInvokeHelper mNativeInvokeHelper;
+  private boolean isCommit=false;
+  private WXGlobalEventReceiver mGlobalEventReceiver=null;
+  private boolean trackComponent;
+  private boolean enableLayerType = true;
+  private boolean mNeedValidate = false;
+  private boolean mNeedReLoad = false;
+  private boolean mUseScroller = false;
+  private int mInstanceViewPortWidth = 750;
+  private boolean enableFullScreenHeight = false;
+  private WXInstanceApm mApmForInstance;
+  private @NonNull
+  FlatGUIContext mFlatGUIContext =new FlatGUIContext();
+
+  private Map<String,String> mContainerInfo;
+
+  public boolean isNewFsEnd = false;
+  private List<JSONObject> componentsInfoExceedGPULimit  = new LinkedList<>();
+
+  /**
+   * bundle type
+   */
+  public BundType bundleType;
+  public long mRenderStartNanos;
+  public int mExecJSTraceId = WXTracing.nextId();
+
+  private boolean isViewDisAppear = false;
+
+  /**
+   *for network tracker
+   */
+  public String mwxDims[] = new String [5];
+  public long measureTimes[] = new long [5];
+
+  public WeakReference<String> templateRef;
+  public Map<String,List<String>> responseHeaders = new HashMap<>();
+
+  /**
+   * Render strategy.
+   */
+  private WXRenderStrategy mRenderStrategy = WXRenderStrategy.APPEND_ASYNC;
+
+  private boolean mDisableSkipFrameworkInit = false;
+
+  /**
+   * Render start time
+   */
+  public long mRenderStartTime;
+  /**
+   * Refresh start time
+   */
+  private long mRefreshStartTime;
+  private WXPerformance mWXPerformance;
+  private ScrollView mScrollView;
+  private WXScrollView.WXScrollViewListener mWXScrollViewListener;
+
+  private List<OnWXScrollListener> mWXScrollListeners;
+
+  private List<String> mLayerOverFlowListeners;
+
+  private List<ActionBarHandler> mWXActionbarHandlers;
+
+  private List<OnBackPressedHandler> mWXBackPressedHandlers;
+
+  private List<OnActivityResultHandler> mWXOnActivityResultHandlers;
+
+  private WXSDKInstance mParentInstance;
+
+  private String mRenderType = RenderTypes.RENDER_TYPE_NATIVE;
+
+  public TimeCalculator mTimeCalculator;
+  /**
+   * Default Width And Viewport is 750,
+   * when screen width change, we adjust viewport to adapter screen change
+   * */
+  private boolean mAutoAdjustDeviceWidth = WXEnvironment.AUTO_ADJUST_ENV_DEVICE_WIDTH;
+
+  public  List<JSONObject> getComponentsExceedGPULimit(){return componentsInfoExceedGPULimit;}
+  @RestrictTo(Scope.LIBRARY)
+  public void setComponentsInfoExceedGPULimit(JSONObject component){
+    if(component!= null && !component.isEmpty()){
+      componentsInfoExceedGPULimit.add(component);
+    }
+  }
+
+  public List<String> getLayerOverFlowListeners() {
+    return mLayerOverFlowListeners;
+  }
+
+  public void addLayerOverFlowListener(String ref) {
+    if (mLayerOverFlowListeners == null)
+      mLayerOverFlowListeners = new ArrayList<>();
+    mLayerOverFlowListeners.add(ref);
+  }
+
+  public void removeLayerOverFlowListener(String ref) {
+    if (mLayerOverFlowListeners != null)
+      mLayerOverFlowListeners.remove(ref);
+  }
+
+  /**
+   * whether we are in preRender mode
+   * */
+  private volatile boolean isPreRenderMode;
+
+  private boolean mCurrentGround = false;
+  private ComponentObserver mComponentObserver;
+  private Map<String, GraphicActionAddElement> inactiveAddElementAction = new ArrayMap<>();
+
+  private Map<Long, ContentBoxMeasurement> mContentBoxMeasurements = new ArrayMap<>();
+
+  private List<InstanceOnFireEventInterceptor> mInstanceOnFireEventInterceptorList;
+
+
+  /**
+   * network handler
+   */
+  public interface ImageNetworkHandler {
+    public String fetchLocal(String url);
+  }
+
+  public interface StreamNetworkHandler {
+    public String fetchLocal(String url);
+  }
+
+  public interface CustomFontNetworkHandler {
+    public String fetchLocal(String url);
+  }
+
+  private ImageNetworkHandler mImageNetworkHandler;
+
+  private StreamNetworkHandler mStreamNetworkHandler;
+
+  private CustomFontNetworkHandler mCustomFontNetworkHandler;
+
+  public ImageNetworkHandler getImageNetworkHandler() {
+    return mImageNetworkHandler;
+  }
+
+  public void setImageNetworkHandler(ImageNetworkHandler imageNetworkHandler) {
+    this.mImageNetworkHandler = imageNetworkHandler;
+  }
+
+  public StreamNetworkHandler getStreamNetworkHandler() {
+    return mStreamNetworkHandler;
+  }
+
+  public void setStreamNetworkHandler(StreamNetworkHandler streamNetworkHandler) {
+    this.mStreamNetworkHandler = streamNetworkHandler;
+  }
+
+  public CustomFontNetworkHandler getCustomFontNetworkHandler() {
+    return mCustomFontNetworkHandler;
+  }
+
+  public void setCustomFontNetworkHandler(CustomFontNetworkHandler customFontNetworkHandler) {
+    this.mCustomFontNetworkHandler = customFontNetworkHandler;
+  }
+
+
+  /**
+   *  ActionBar Handler
+   */
+
+  public interface ActionBarHandler {
+    boolean onSupportNavigateUp();
+  }
+
+  public interface OnBackPressedHandler {
+    boolean onBackPressed();
+  }
+
+  public static abstract class OnActivityResultHandler {
+    private String id;
+
+    public OnActivityResultHandler(String id) {
+      this.id = id;
+    }
+
+    public abstract boolean onActivityResult(int requestCode, int resultCode, Intent data, String id);
+
+    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
+      return onActivityResult(requestCode, resultCode, data, id);
+    }
+  }
+
+  /**
+   * set make weexCore run in single process mode
+   * @param flag true means weexCore run in single process mode or multi process mode
+   */
+  public void setUseSingleProcess(boolean flag) {
+    WXBridgeManager.getInstance().setUseSingleProcess(flag);
+  }
+
+  /**
+   * set open SandBox
+   * @param flag
+   */
+  public void setUseSandBox(boolean flag) {
+    WXBridgeManager.getInstance().setSandBoxContext(flag);
+  }
+
+  public PriorityQueue<WXEmbed> hiddenEmbeds;
+
+  private int maxHiddenEmbedsNum = -1; //max hidden embed num, -1 standard for ulimit
+
+  public int getMaxHiddenEmbedsNum() {
+    return maxHiddenEmbedsNum;
+  }
+
+  public void setMaxHiddenEmbedsNum(int maxHiddenEmbedsNum) {
+    this.maxHiddenEmbedsNum = maxHiddenEmbedsNum;
+  }
+
+  @WorkerThread
+  @RestrictTo(Scope.LIBRARY)
+  public void addInActiveAddElementAction(String ref, GraphicActionAddElement action){
+    inactiveAddElementAction.put(ref, action);
+  }
+
+  @WorkerThread
+  @RestrictTo(Scope.LIBRARY)
+  public void removeInActiveAddElmentAction(String ref){
+    inactiveAddElementAction.remove(ref);
+  }
+
+  @WorkerThread
+  @RestrictTo(Scope.LIBRARY)
+  public GraphicActionAddElement getInActiveAddElementAction(String ref){
+    return inactiveAddElementAction.get(ref);
+  }
+
+  /**
+   * If anchor is created manually(etc. define a layout xml resource ),
+   * be aware do not add it to twice when {@link IWXRenderListener#onViewCreated(WXSDKInstance, View)}.
+   * @param a
+   */
+  public void setRenderContainer(RenderContainer a){
+     setWXAbstractRenderContainer(a);
+  }
+
+  public void setWXAbstractRenderContainer(WXAbstractRenderContainer a){
+    if(a != null) {
+      a.setSDKInstance(this);
+      a.addOnLayoutChangeListener(this);
+    }
+
+    mRenderContainer = a;
+    if (mRenderContainer != null && mRenderContainer.getLayoutParams() != null
+            && mRenderContainer.getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
+      WXBridgeManager.getInstance().post(new Runnable() {
+        @Override
+        public void run() {
+          WXBridgeManager.getInstance().setRenderContentWrapContentToCore(true, getInstanceId());
+        }
+      });
+    } else {
+      WXBridgeManager.getInstance().post(new Runnable() {
+        @Override
+        public void run() {
+          WXBridgeManager.getInstance().setRenderContentWrapContentToCore(false, getInstanceId());
+        }
+      });
+    }
+  }
+
+  private int mMaxDeepLayer;
+
+  public boolean isTrackComponent() {
+    return trackComponent;
+  }
+
+  public void setTrackComponent(boolean trackComponent) {
+    this.trackComponent = trackComponent;
+  }
+
+  /**
+   * Tell whether it is enabled to change the layerType
+   * {@link android.view.View#setLayerType(int, Paint)}
+   * @return True for enable to change the layerType of component, false otherwise. The default
+   * is True
+   */
+  public boolean isLayerTypeEnabled() {
+    return enableLayerType;
+  }
+
+  /**
+   * Enable the ability of changing layerType. e.g. {@link android.view.View#setLayerType(int, Paint)}
+   * Disable the ability of changing layerType will have tremendous <strong>performance
+   * punishment</strong>.
+   *
+   * <strong>Do not</strong> set this to false unless you know exactly what you are doing.
+   * @param enable True for enable to change the layerType of component, false otherwise. The default
+   * is True
+   */
+  public void enableLayerType(boolean enable) {
+    enableLayerType = enable;
+  }
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public @NonNull
+  FlatGUIContext getFlatUIContext(){
+    return mFlatGUIContext;
+  }
+
+  public boolean isNeedValidate() {
+    return mNeedValidate;
+  }
+
+  public boolean isNeedReLoad() {
+    return mNeedReLoad;
+  }
+
+  public void setNeedLoad(boolean load) {
+    mNeedReLoad = load;
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  public void  setEnableFullScreenHeight(boolean fullScreenHeight){enableFullScreenHeight = fullScreenHeight;}
+
+  @RestrictTo(Scope.LIBRARY)
+  public boolean isFullScreenHeightEnabled(){return enableFullScreenHeight;}
+
+  public boolean isUseScroller() {
+    return mUseScroller;
+  }
+
+  public void setUseScroller(boolean use) {
+    mUseScroller = use;
+  }
+
+  public void setInstanceViewPortWidth(int instanceViewPortWidth) {
+    setInstanceViewPortWidth(instanceViewPortWidth,false);
+
+  }
+  public void setInstanceViewPortWidth(int instanceViewPortWidth,boolean fromMetaModule){
+    this.mInstanceViewPortWidth = instanceViewPortWidth;
+    this.mAutoAdjustDeviceWidth = false;
+    if(!fromMetaModule){
+      WXBridgeManager.getInstance().setViewPortWidth(getInstanceId(), mInstanceViewPortWidth);
+    }
+  }
+  public void resetDeviceDisplayOfPage(){
+    WXBridgeManager.getInstance().setDeviceDisplayOfPage(getInstanceId(), WXViewUtils.getScreenWidth(getContext()), WXViewUtils.getScreenHeight(getContext()));
+  }
+  public void setPageKeepRawCssStyles(){
+    WXBridgeManager.getInstance().setPageArgument(getInstanceId(),"reserveCssStyles","true");
+  }
+  public void reloadPageLayout(){
+    WXBridgeManager.getInstance().reloadPageLayout(getInstanceId());
+  }
+
+  public void setAutoAdjustDeviceWidth(boolean autoAdjustViewPort){
+    this.mAutoAdjustDeviceWidth = autoAdjustViewPort;
+  }
+
+  public boolean isAutoAdjustDeviceWidth(){
+    return mAutoAdjustDeviceWidth;
+  }
+
+  private void setDeviceDisplay(float deviceWith, float deviceHeight, float scale){
+    WXBridgeManager.getInstance().setDeviceDisplay(getInstanceId(), deviceWith, deviceHeight, scale);
+  }
+
+
+
+  public int getInstanceViewPortWidth(){
+    return mInstanceViewPortWidth;
+  }
+
+  public interface OnInstanceVisibleListener{
+    void onAppear();
+    void onDisappear();
+  }
+  private List<OnInstanceVisibleListener> mVisibleListeners = new ArrayList<>();
+
+  public WXSDKInstance(Context context) {
+    mInstanceId = WXSDKManager.getInstance().generateInstanceId();
+    init(context);
+  }
+
+  //for preInit
+  public WXSDKInstance(){
+    mInstanceId = WXSDKManager.getInstance().generateInstanceId();
+    mWXPerformance = new WXPerformance(mInstanceId);
+    mApmForInstance = new WXInstanceApm(mInstanceId);
+    WXSDKManager.getInstance().getAllInstanceMap().put(mInstanceId,this);
+    mTimeCalculator = new TimeCalculator(this);
+  }
+
+
+  /**
+   * For unittest only.
+   */
+  @RestrictTo(Scope.TESTS)
+  WXSDKInstance(Context context,String id) {
+    mInstanceId = id;
+    init(context);
+  }
+
+  public WXComponent getRootComponent() {
+    return mRootComp;
+  }
+
+  public void setNestedInstanceInterceptor(NestedInstanceInterceptor interceptor){
+    mNestedInstanceInterceptor = interceptor;
+  }
+
+  public final WXSDKInstance createNestedInstance(NestedContainer container){
+    WXSDKInstance sdkInstance = newNestedInstance();
+    if(mNestedInstanceInterceptor != null){
+      mNestedInstanceInterceptor.onCreateNestInstance(sdkInstance,container);
+    }
+    if(sdkInstance != null){
+        sdkInstance.setComponentObserver(this.getComponentObserver());
+    }
+    return sdkInstance;
+  }
+
+  protected WXSDKInstance newNestedInstance() {
+    return new WXSDKInstance(mContext);
+  }
+  public boolean isHasException() {
+    return hasException;
+  }
+
+  public void setHasException(boolean hasException) {
+    this.hasException = hasException;
+  }
+
+  public void createInstanceFuncHeartBeat() {
+    WXLogUtils.d("createInstanceFuncHeartBeat: " + mInstanceId);
+    this.createInstanceHeartBeat = true;
+    getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_END_EXCUTE_BUNDLE);
+  }
+
+  public void addOnInstanceVisibleListener(OnInstanceVisibleListener l){
+    mVisibleListeners.add(l);
+  }
+
+  public void removeOnInstanceVisibleListener(OnInstanceVisibleListener l){
+    mVisibleListeners.remove(l);
+  }
+
+  public void init(Context context) {
+    RegisterCache.getInstance().idle(true);
+    mContext = context;
+    mContainerInfo = new HashMap<>(4);
+    mNativeInvokeHelper = new NativeInvokeHelper(mInstanceId);
+
+    if (null == mWXPerformance){
+      mWXPerformance = new WXPerformance(mInstanceId);
+    }
+    if (null == mApmForInstance){
+      mApmForInstance = new WXInstanceApm(mInstanceId);
+    }
+
+    mWXPerformance.WXSDKVersion = WXEnvironment.WXSDK_VERSION;
+    mWXPerformance.JSLibInitTime = WXEnvironment.sJSLibInitTime;
+
+    mUserTrackAdapter=WXSDKManager.getInstance().getIWXUserTrackAdapter();
+
+    WXSDKManager.getInstance().getAllInstanceMap().put(mInstanceId,this);
+
+    mContainerInfo.put(WXInstanceApm.KEY_PAGE_PROPERTIES_CONTAINER_NAME, context instanceof Activity
+            ? context.getClass().getSimpleName()
+            :"unKnowContainer"
+    );
+    mContainerInfo.put(WXInstanceApm.KEY_PAGE_PROPERTIES_INSTANCE_TYPE,"page");
+
+    // WXBridgeManager.getInstance().checkJsEngineMultiThread();
+    mDisableSkipFrameworkInit = isDisableSkipFrameworkInDataRender();
+
+    if(mTimeCalculator == null) {
+      mTimeCalculator = new TimeCalculator(this);
+    }
+  }
+
+  /**
+   * Set a Observer for component.
+   * This observer will be called in each component, should not doing
+   * anything will impact render performance.
+   *
+   * @param observer
+   */
+  public void setComponentObserver(ComponentObserver observer){
+    mComponentObserver = observer;
+  }
+
+  public ComponentObserver getComponentObserver(){
+    return mComponentObserver;
+  }
+
+  public NativeInvokeHelper getNativeInvokeHelper() {
+    return mNativeInvokeHelper;
+  }
+
+  @Deprecated
+  public void setBizType(String bizType) {
+    if (!TextUtils.isEmpty(bizType)) {
+      mWXPerformance.bizType = bizType;
+    }
+  }
+
+  public ScrollView getScrollView() {
+    return mScrollView;
+  }
+
+  public void setRootScrollView(ScrollView scrollView) {
+    mScrollView = scrollView;
+    if (mWXScrollViewListener != null && mScrollView instanceof WXScrollView) {
+      ((WXScrollView) mScrollView).addScrollViewListener(mWXScrollViewListener);
+    }
+  }
+
+  @Deprecated
+  public void registerScrollViewListener(WXScrollView.WXScrollViewListener scrollViewListener) {
+    mWXScrollViewListener = scrollViewListener;
+  }
+
+  @Deprecated
+  public WXScrollView.WXScrollViewListener getScrollViewListener() {
+    return mWXScrollViewListener;
+  }
+
+  @Deprecated
+  public void setIWXUserTrackAdapter(IWXUserTrackAdapter adapter) {
+  }
+
+  public void setContainerInfo(String key,String val){
+    mContainerInfo.put(key,val);
+  }
+
+  public Map<String, String> getContainerInfo() {
+    return mContainerInfo;
+  }
+
+  /**
+   * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy
+   * @param template bundle js
+   * @param options  os   iphone/android/ipad
+   *                 weexversion    Weex version(like 1.0.0)
+   *                 appversion     App version(like 1.0.0)
+   *                 devid        Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH)
+   *                 sysversion    Device system version(like 5.4.4、7.0.4, should be used with os)
+   *                 sysmodel     Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE")
+   *                 Time    UNIX timestamp, UTC+08:00
+   *                 TTID(Optional)
+   *                 MarkertId
+   *                 Appname(Optional)  tm,tb,qa
+   *                 Bundleurl(Optional)  template url
+   * @param jsonInitData Initial data for rendering
+   */
+  public void render(String template, Map<String, Object> options, String jsonInitData) {
+    render(template, options, jsonInitData, WXRenderStrategy.APPEND_ASYNC);
+  }
+
+  /**
+   * Render template asynchronously
+   * @param template bundle js
+   * @param options  os   iphone/android/ipad
+   *                 weexversion    Weex version(like 1.0.0)
+   *                 appversion     App version(like 1.0.0)
+   *                 devid        Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH)
+   *                 sysversion    Device system version(like 5.4.4、7.0.4, should be used with os)
+   *                 sysmodel     Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE")
+   *                 Time    UNIX timestamp, UTC+08:00
+   *                 TTID(Optional)
+   *                 MarkertId
+   *                 Appname(Optional)  tm,tb,qa
+   *                 Bundleurl(Optional)  template url
+   * @param jsonInitData Initial data for rendering
+   * @param flag     RenderStrategy {@link WXRenderStrategy}
+   */
+  @Deprecated
+  public void render(String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) {
+    render(WXPerformance.DEFAULT, template, options, jsonInitData, flag);
+  }
+
+  /**
+   * Render template asynchronously
+   *
+   * @param pageName, used for performance log.
+   * @param template bundle js
+   * @param options  os   iphone/android/ipad
+   *                 weexversion    Weex version(like 1.0.0)
+   *                 appversion     App version(like 1.0.0)
+   *                 devid        Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH)
+   *                 sysversion    Device system version(like 5.4.4、7.0.4, should be used with os)
+   *                 sysmodel     Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE")
+   *                 Time    UNIX timestamp, UTC+08:00
+   *                 TTID(Optional)
+   *                 MarkertId
+   *                 Appname(Optional)  tm,tb,qa
+   *                 Bundleurl(Optional)  template url
+   * @param jsonInitData Initial data for rendering
+   * @param flag     RenderStrategy {@link WXRenderStrategy}
+   */
+  public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) {
+    render(pageName, new Script(template), options, jsonInitData, flag);
+  }
+
+  public void render(String pageName, Script template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) {
+    mWXPerformance.beforeInstanceRender(mInstanceId);
+
+    if(WXEnvironment.isApkDebugable() && WXPerformance.DEFAULT.equals(pageName)){
+
+      if (getUIContext() != null) {
+        new AlertDialog.Builder(getUIContext())
+                .setTitle("Error: Missing pageName")
+                .setMessage("We highly recommend you to set pageName. Call" +
+                        "\nWXSDKInstance#render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag)\n" +
+                        "to fix it.")
+                .show();
+      }
+
+      return;
+    }
+    renderInternal(pageName,template,options,jsonInitData,flag);
+  }
+
+  /**
+   * Render binary template asynchronously in DATA_RENDER_BINARY strategy.
+   */
+  public void render(String pageName, byte[] template, Map<String, Object> options, String jsonInitData) {
+    render(pageName, new Script(template), options, jsonInitData, WXRenderStrategy.DATA_RENDER_BINARY);
+  }
+
+  private void ensureRenderArchor(){
+    if(mRenderContainer == null){
+      if (getContext() != null) {
+        setRenderContainer(new RenderContainer(getContext()));
+        mRenderContainer.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+        mRenderContainer.setBackgroundColor(Color.TRANSPARENT);
+        mRenderContainer.setSDKInstance(this);
+        mRenderContainer.addOnLayoutChangeListener(this);
+      }
+    }
+  }
+
+  private void renderInternal(String pageName,
+                              String template,
+                              Map<String, Object> options,
+                              String jsonInitData,
+                              WXRenderStrategy flag) {
+    if (mRendered || TextUtils.isEmpty(template)) {
+      return;
+    }
+    renderInternal(pageName, new Script(template), options, jsonInitData, flag);
+  }
+
+  private boolean isPreInit = false;
+  public boolean isPreInitMode(){
+    return isPreInit;
+  }
+
+  private boolean isPreDownLoad =false;
+  public boolean isPreDownLoad(){
+    return isPreDownLoad;
+  }
+
+  public void onInstanceReady(){
+    WXLogUtils.d("test->","onInstanceReady");
+    mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_CONTAINER_READY);
+    if (!isPreInit && !isPreDownLoad){
+      return;
+    }
+    mApmForInstance.onInstanceReady(isPreDownLoad);
+    if (isPreDownLoad){
+        mHttpListener.onInstanceReady();
+    }
+  }
+
+  public void preInit(String pageName,
+                      String script,
+                      Map<String, Object> options,
+                      String jsonInitData,
+                      WXRenderStrategy flag){
+    isPreInit = true;
+    mRenderStrategy = flag;
+    Map<String, Object> renderOptions = options;
+    if (renderOptions == null) {
+      renderOptions = new HashMap<>();
+    }
+    //mApmForInstance.doInit();
+    mApmForInstance.isReady = false;
+    WXSDKManager.getInstance().createInstance(this, new Script(script), renderOptions, jsonInitData);
+  }
+
+  public void preDownLoad(String url,
+                          Map<String, Object> options,
+                          String jsonInitData,
+                          WXRenderStrategy flag){
+    this.isPreDownLoad =true;
+    mRenderStrategy = flag;
+    mApmForInstance.isReady = false;
+    renderByUrl(url,url,options,jsonInitData,flag);
+  }
+
+
+  private void renderInternal(String pageName,
+                              Script template,
+                              Map<String, Object> options,
+                              String jsonInitData,
+                              WXRenderStrategy flag){
+    if (mRendered || template == null || template.isEmpty()) {
+      return;
+    }
+
+    LogDetail logDetail = mTimeCalculator.createLogDetail("renderInternal");
+    mRenderStrategy = flag;
+
+    //some case ,from render(template),but not render (url)
+    if (!mApmForInstance.hasInit()){
+      mApmForInstance.doInit();
+    }
+    mApmForInstance.setPageName(pageName);
+    mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN);
+    mApmForInstance.doDelayCollectData();
+
+    mWXPerformance.pageName = (TextUtils.isEmpty(pageName) ? "defaultBundleUrl":pageName);
+    if (TextUtils.isEmpty(mBundleUrl)) {
+      mBundleUrl = mWXPerformance.pageName;
+    }
+
+    if (WXTracing.isAvailable()) {
+      WXTracing.TraceEvent traceEvent = WXTracing.newEvent("executeBundleJS", mInstanceId, -1);
+      traceEvent.traceId = mExecJSTraceId;
+      traceEvent.iid = mInstanceId;
+      traceEvent.tname = "JSThread";
+      traceEvent.ph = "B";
+      traceEvent.submit();
+      mRenderStartNanos = System.nanoTime();
+    }
+
+    ensureRenderArchor();
+
+    Map<String, Object> renderOptions = options;
+    if (renderOptions == null) {
+      renderOptions = new HashMap<>();
+    }
+
+    if (WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && renderOptions.get("dynamicMode") == null) {
+      renderOptions.put("dynamicMode", "true");
+      renderByUrl(pageName, WXEnvironment.sDynamicUrl, renderOptions, jsonInitData, flag);
+      return;
+    }
+
+    TimeCalculator timeCalculator = new TimeCalculator(this);
+
+    mWXPerformance.JSTemplateSize = template.length() / 1024f;
+    mApmForInstance.addStats(WXInstanceApm.KEY_PAGE_STATS_BUNDLE_SIZE,mWXPerformance.JSTemplateSize);
+    mRenderStartTime = System.currentTimeMillis();
+    WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName);
+    if(mAutoAdjustDeviceWidth && WXDeviceUtils.isAutoResize(mContext)){
+         if(WXEnvironment.AUTO_UPDATE_APPLICATION_SCREEN_SIZE) {
+             WXViewUtils.updateApplicationScreen(mContext);
+         }
+         WXParams params = WXBridgeManager.getInstance().getInitParams();
+         if(params != null && !TextUtils.equals(params.getDeviceWidth(), String.valueOf(WXViewUtils.getScreenWidth(mContext)))){
+           params.setDeviceWidth(String.valueOf(WXViewUtils.getScreenWidth(mContext)));
+           params.setDeviceHeight(String.valueOf(WXViewUtils.getScreenHeight(mContext)));
+           float density = WXEnvironment.sApplication.getResources().getDisplayMetrics().density;
+           WXEnvironment.addCustomOptions(WXConfig.scale, Float.toString(density));
+           String statusBarHeight =  null;
+           if(WXViewUtils.getStatusBarHeight(mContext) > 0 ){
+             statusBarHeight = String.valueOf(WXViewUtils.getStatusBarHeight(mContext));
+           }
+           WXBridgeManager.getInstance().updateInitDeviceParams(params.getDeviceWidth(),
+                                                                params.getDeviceHeight(),
+                                                                Float.toString(density), statusBarHeight);
+           setDeviceDisplay(WXViewUtils.getScreenWidth(mContext),
+                            WXViewUtils.getScreenHeight(mContext),
+                            WXViewUtils.getScreenDensity(mContext));
+         }
+    }
+    logDetail.taskStart();
+    if (isPreInitMode()){
+      getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_START);
+      WXBridgeManager.getInstance().loadJsBundleInPreInitMode(getInstanceId(),template.getContent());
+    } else {
+      WXSDKManager.getInstance().createInstance(this, template, renderOptions, jsonInitData);
+    }
+    logDetail.taskEnd();
+    mRendered = true;
+
+    final IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
+
+    if(wxJscProcessManager != null && wxJscProcessManager.shouldReboot()) {
+      WXSDKManager.getInstance().postOnUiThread(new Runnable() {
+        @Override
+        public void run() {
+          checkWhiteScreen();
+          if(isDestroy || hasException || isRenderSuccess) {
+            return;
+          }
+
+          // there is no need to reboot js engine if render by eagle
+          if(isDataRender()) {
+            return;
+          }
+
+          View containerView = getContainerView();
+          if(containerView instanceof ViewGroup) {
+            if(0 == ((ViewGroup) containerView).getChildCount()) {
+              if(wxJscProcessManager.withException(WXSDKInstance.this)) {
+                onJSException(String.valueOf(WXErrorCode.WX_ERR_RELOAD_PAGE),"jsc reboot","jsc reboot");
+              }
+              if(!createInstanceHeartBeat) {
+                  WXBridgeManager.getInstance().callReportCrashReloadPage(mInstanceId, null);
+                  WXLogUtils.e("callReportCrashReloadPage with jsc reboot");
+              }
+            }
+          }
+        }
+      }, wxJscProcessManager.rebootTimeout());
+    }
+  }
+
+
+  private void checkWhiteScreen(){
+    if (isDestroy ||!WhiteScreenUtils.doWhiteScreenCheck()){
+      return;
+    }
+
+    boolean isWS = WhiteScreenUtils.isWhiteScreen(this);
+    if (!isWS){
+      return;
+    }
+    WXErrorCode errorCode = createInstanceHeartBeat?WXErrorCode.WX_ERROR_WHITE_SCREEN:WXErrorCode.WHITE_SCREEN_RESPONSE_TIMEOUT;
+    if (WXBridgeManager.getInstance().isRebootExceedLimit()){
+      errorCode = WXErrorCode.WHITE_SCREEN_REBOOT_EXCEED_LIMIT;
+    }
+    Map<String,String> args = new HashMap<>(1);
+    String vieTreeMsg = WhiteScreenUtils.takeViewTreeSnapShot(this);
+    args.put("viewTree",null == vieTreeMsg?"null viewTreeMsg":vieTreeMsg);
+    args.put("weexCoreThreadStackTrace",WXBridgeManager.getInstance().getWeexCoreThreadStackTrace());
+
+    for (Map.Entry<String,String> entry: WXStateRecord.getInstance().getStateInfo().entrySet()){
+      args.put(entry.getKey(),entry.getValue());
+    }
+    WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),errorCode,"checkEmptyScreen",errorCode.getErrorMsg(),args);
+  }
+
+
+  public boolean skipFrameworkInit(){
+    return isDataRender() && !mDisableSkipFrameworkInit;
+  }
+
+  private boolean isDataRender() {
+    return getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY || getRenderStrategy() == WXRenderStrategy.DATA_RENDER;
+  }
+
+  private void renderByUrlInternal(String pageName,
+                                   final String url,
+                                   Map<String, Object> options,
+                                   final String jsonInitData,
+                                   WXRenderStrategy flag) {
+
+
+    LogDetail logDetail = mTimeCalculator.createLogDetail("renderByUrlInternal");
+    logDetail.taskStart();
+    ensureRenderArchor();
+    pageName = wrapPageName(pageName, url);
+    mBundleUrl = url;
+    mRenderStrategy = flag;
+    if(WXSDKManager.getInstance().getValidateProcessor()!=null) {
+      mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl);
+    }
+
+    Map<String, Object> renderOptions = options;
+    if (renderOptions == null) {
+      renderOptions = new HashMap<>();
+    }
+    if (!renderOptions.containsKey(BUNDLE_URL)) {
+      renderOptions.put(BUNDLE_URL, url);
+    }
+
+    getWXPerformance().pageName = pageName;
+
+    mApmForInstance.doInit();
+    mApmForInstance.setPageName(pageName);
+
+    Uri uri = Uri.parse(url);
+    if (uri != null && TextUtils.equals(uri.getScheme(), "file")) {
+      mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
+      String template = WXFileUtils.loadFileOrAsset(assembleFilePath(uri), mContext);
+      mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END);
+      render(pageName,template , renderOptions, jsonInitData, flag);
+      return;
+    }
+
+    boolean is_wlasm = false;
+    if (uri != null && uri.getPath()!=null) {
+      if(uri.getPath().endsWith(".wlasm")){
+        is_wlasm =  true;
+      }
+    }
+    if (is_wlasm){
+      flag = WXRenderStrategy.DATA_RENDER_BINARY;
+    }
+
+    IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter();
+
+    WXRequest wxRequest = new WXRequest();
+    wxRequest.url = rewriteUri(Uri.parse(url), URIAdapter.BUNDLE).toString();
+    if(wxRequest != null && !TextUtils.isEmpty(wxRequest.url)){
+      requestUrl = wxRequest.url;
+    }else {
+      requestUrl = pageName;
+    }
+
+    if (wxRequest.paramMap == null) {
+      wxRequest.paramMap = new HashMap<String, String>();
+    }
+    wxRequest.instanceId = getInstanceId();
+    wxRequest.paramMap.put(KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(mContext,WXEnvironment.getConfig()));
+    wxRequest.paramMap.put("isBundleRequest","true");
+    mHttpListener = new WXHttpListener(this, pageName, renderOptions, jsonInitData, flag, System.currentTimeMillis());
+    mHttpListener.isPreDownLoadMode = isPreDownLoad;
+    mHttpListener.setSDKInstance(this);
+    mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
+    adapter.sendRequest(wxRequest, (IWXHttpAdapter.OnHttpListener) mHttpListener);
+    logDetail.taskEnd();
+  }
+
+  private WXHttpListener mHttpListener = null;
+
+  /**
+   * Use {@link #render(String, String, Map, String, WXRenderStrategy)} instead.
+   * @param pageName
+   * @param template
+   * @param options
+   * @param jsonInitData
+   * @param width
+   * @param height
+   * @param flag
+   */
+  @Deprecated
+  public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, int width, int height, WXRenderStrategy flag) {
+    render(pageName,template,options,jsonInitData,flag);
+  }
+
+  /**
+   * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy
+   * @param template bundle js
+   */
+  public void render(String template) {
+    render(WXPerformance.DEFAULT, template, null, null, mRenderStrategy);
+  }
+
+  /**
+   * Use {@link #render(String)} instead.
+   * @param template
+   * @param width
+   * @param height
+   */
+  @Deprecated
+  public void render(String template, int width, int height) {
+    render(template);
+  }
+
+  /**
+   * Use {@link #renderByUrl(String, String, Map, String, WXRenderStrategy)} instead.
+   * @param pageName
+   * @param url
+   * @param options
+   * @param jsonInitData
+   * @param width
+   * @param height
+   * @param flag
+   */
+  @Deprecated
+  public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final int width, final int height, final WXRenderStrategy flag){
+    renderByUrl(pageName,url,options,jsonInitData,flag);
+  }
+
+  public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final WXRenderStrategy flag) {
+    renderByUrlInternal(pageName,url,options,jsonInitData,flag);
+  }
+
+  private String wrapPageName(String pageName, String url) {
+    if(TextUtils.equals(pageName, WXPerformance.DEFAULT)){
+      pageName = url;
+      WXExceptionUtils.degradeUrl = pageName;
+      try {
+        Uri uri=Uri.parse(url);
+        if(uri!=null){
+          Uri.Builder builder=new Uri.Builder();
+          builder.scheme(uri.getScheme());
+          builder.authority(uri.getAuthority());
+          builder.path(uri.getPath());
+          pageName=builder.toString();
+        }
+      } catch (Exception e) {
+      }
+    }
+    return pageName;
+  }
+
+  private String assembleFilePath(Uri uri) {
+    if(uri!=null && uri.getPath()!=null){
+      return uri.getPath().replaceFirst("/","");
+    }
+    return "";
+  }
+
+  public void reloadPage(boolean reloadThis) {
+
+    WXSDKEngine.reload();
+
+    if (reloadThis) {
+      if (mContext != null)  {
+        Intent intent = new Intent();
+        intent.setAction(ACTION_INSTANCE_RELOAD);
+        intent.putExtra("url", mBundleUrl);
+        mContext.sendBroadcast(intent);
+      }
+      // mRendered = false;
+      //    destroy();
+      // renderInternal(mPackage, mTemplate, mOptions, mJsonInitData, mFlag);
+      // refreshInstance("{}");
+    } else {
+      IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+      if (adapter != null) {
+        boolean degrade = Boolean.parseBoolean(adapter
+                .getConfig("android_weex_ext_config",
+                        "degrade_to_h5_if_not_reload",
+                        "true"));
+        WXLogUtils.e("degrade : " + degrade);
+        if(degrade) {
+          onJSException(String.valueOf(WXErrorCode.WX_ERR_RELOAD_PAGE.getErrorCode()),"Do not reloadPage", "Do not reloadPage degradeToH5");
+          WXLogUtils.e("Do not reloadPage degradeToH5");
+        }
+      }
+    }
+  }
+
+  /**
+   * Refresh instance asynchronously.
+   * @param data the new data
+   */
+  public void refreshInstance(Map<String, Object> data) {
+    if (data == null) {
+      return;
+    }
+    refreshInstance(WXJsonUtils.fromObjectToJSONString(data));
+  }
+
+  /**
+   * Refresh instance asynchronously.
+   * @param jsonData the new data
+   */
+  public void refreshInstance(String jsonData) {
+    if (jsonData == null) {
+      return;
+    }
+    mRefreshStartTime = System.currentTimeMillis();
+    //cancel last refresh message
+    if (mLastRefreshData != null) {
+      mLastRefreshData.isDirty = true;
+    }
+
+    mLastRefreshData = new WXRefreshData(jsonData, false);
+
+    WXSDKManager.getInstance().refreshInstance(mInstanceId, mLastRefreshData);
+  }
+
+  public WXRenderStrategy getRenderStrategy() {
+    return mRenderStrategy;
+  }
+
+  public Context getUIContext() {
+    return mContext;
+  }
+
+  public String getInstanceId() {
+    return mInstanceId;
+  }
+
+  public Context getContext() {
+    return mContext;
+  }
+
+  public int getWeexHeight() {
+    return mRenderContainer == null ? 0: mRenderContainer.getHeight();
+  }
+
+  public int getWeexWidth() {
+    return mRenderContainer == null ? 0: mRenderContainer.getWidth();
+  }
+
+
+  public IWXImgLoaderAdapter getImgLoaderAdapter() {
+    return WXSDKManager.getInstance().getIWXImgLoaderAdapter();
+  }
+
+  public IDrawableLoader getDrawableLoader() {
+    return WXSDKManager.getInstance().getDrawableLoader();
+  }
+
+  public URIAdapter getURIAdapter(){
+    return WXSDKManager.getInstance().getURIAdapter();
+  }
+
+  public Uri rewriteUri(Uri uri,String type){
+    return getURIAdapter().rewrite(this,type,uri);
+  }
+
+  public IWXHttpAdapter getWXHttpAdapter() {
+    return WXSDKManager.getInstance().getIWXHttpAdapter();
+  }
+
+  public IWXStatisticsListener getWXStatisticsListener() {
+    return mStatisticsListener;
+  }
+
+  public @Nullable
+  IWebSocketAdapter getWXWebSocketAdapter() {
+    return WXSDKManager.getInstance().getIWXWebSocketAdapter();
+  }
+
+  @Deprecated
+  public void reloadImages() {
+    if (mScrollView == null) {
+      return;
+    }
+  }
+
+
+  public boolean isPreRenderMode() {
+    return this.isPreRenderMode;
+  }
+
+  public void setPreRenderMode(final boolean isPreRenderMode) {
+    WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
+      @Override
+      public void run() {
+        WXSDKInstance.this.isPreRenderMode = isPreRenderMode;
+      }
+    },0);
+  }
+
+  public void setContext(@NonNull Context context) {
+    this.mContext = context;
+  }
+
+  /********************************
+   * begin register listener
+   ********************************************************/
+  public void registerRenderListener(IWXRenderListener listener) {
+    mRenderListener = listener;
+  }
+
+  @Deprecated
+  public void registerActivityStateListener(IWXActivityStateListener listener) {
+
+  }
+
+  public void registerStatisticsListener(IWXStatisticsListener listener) {
+    mStatisticsListener = listener;
+  }
+
+  /**set render start time*/
+  public void setRenderStartTime(long renderStartTime) {
+    this.mRenderStartTime = renderStartTime;
+  }
+
+  /********************************
+   * end register listener
+   ********************************************************/
+
+
+  /********************************
+   *  begin hook Activity life cycle callback
+   ********************************************************/
+
+  @Override
+  public void onActivityCreate() {
+
+    // module listen Activity onActivityCreate
+    WXModuleManager.onActivityCreate(getInstanceId());
+
+    if(mRootComp != null) {
+      mRootComp.onActivityCreate();
+    }else{
+        if (WXEnvironment.isApkDebugable()){
+            WXLogUtils.w("Warning :Component tree has not build completely,onActivityCreate can not be call!");
+        }
+    }
+
+    mGlobalEventReceiver=new WXGlobalEventReceiver(this);
+    try {
+      getContext().registerReceiver(mGlobalEventReceiver, new IntentFilter(WXGlobalEventReceiver.EVENT_ACTION));
+    } catch (Throwable e) {
+      // Huawei may throw a exception if register more than 500 BroadcastReceivers
+      WXLogUtils.e(e.getMessage());
+      mGlobalEventReceiver = null;
+    }
+
+  }
+
+  @Override
+  public void onActivityStart() {
+
+    // module listen Activity onActivityCreate
+    WXModuleManager.onActivityStart(getInstanceId());
+    if(mRootComp != null) {
+      mRootComp.onActivityStart();
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!");
+
+        }
+    }
+
+  }
+
+  public boolean onCreateOptionsMenu(Menu menu) {
+
+    WXModuleManager.onCreateOptionsMenu(getInstanceId(),menu);
+    if(mRootComp != null) {
+      mRootComp.onCreateOptionsMenu(menu);
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!");
+
+        }
+    }
+    return true;
+  }
+
+  @Override
+  public void onActivityPause() {
+    onViewDisappear();
+    if(!isCommit){
+      if(mUseScroller){
+        mWXPerformance.useScroller=1;
+      }
+      mWXPerformance.maxDeepViewLayer=getMaxDeepLayer();
+      mWXPerformance.wxDims = mwxDims;
+      mWXPerformance.measureTimes = measureTimes;
+      if (mUserTrackAdapter != null) {
+        mUserTrackAdapter.commit(mContext, null, IWXUserTrackAdapter.LOAD, mWXPerformance, getUserTrackParams());
+      }
+      isCommit=true;
+    }
+    // module listen Activity onActivityPause
+    WXModuleManager.onActivityPause(getInstanceId());
+    if(mRootComp != null) {
+      mRootComp.onActivityPause();
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely,onActivityPause can not be call!");
+        }
+    }
+
+    if (!mCurrentGround) {
+      WXLogUtils.i("Application to be in the backround");
+      Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION);
+      intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.PAUSE_EVENT);
+      intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId());
+      /**
+       *  Fix NPE just like {@link #onActivityResume()}
+       */
+      if (null != mContext){
+        mContext.sendBroadcast(intent);
+      }else {
+        try {
+          WXEnvironment.getApplication().sendBroadcast(intent);
+        } catch (Exception e){
+          WXLogUtils.e("weex",e);
+        }
+      }
+      this.mCurrentGround = true;
+    }
+
+    //component appear
+    if((WXEnvironment.isApkDebugable() || WXEnvironment.isPerf()) && mApmForInstance != null){
+        WXLogUtils.e("PerformanceData " + mApmForInstance.toPerfString());
+    }
+  }
+
+
+  @Override
+  public void onActivityResume() {
+
+    // notify onActivityResume callback to module
+    WXModuleManager.onActivityResume(getInstanceId());
+
+    if(mRootComp != null) {
+      mRootComp.onActivityResume();
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely, onActivityResume can not be call!");
+        }
+    }
+
+    if (mCurrentGround) {
+      WXLogUtils.i("Application  to be in the foreground");
+      Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION);
+      intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.RESUME_EVENT);
+      intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId());
+      //todo tmp solution for gray version
+      if (null != mContext){
+        mContext.sendBroadcast(intent);
+      }else {
+        WXEnvironment.getApplication().sendBroadcast(intent);
+      }
+      this.mCurrentGround = false;
+    }
+
+    onViewAppear();
+  }
+
+  @Override
+  public void onActivityStop() {
+
+    // notify onActivityResume callback to module
+    WXModuleManager.onActivityStop(getInstanceId());
+
+    if(mRootComp != null) {
+      mRootComp.onActivityStop();
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely, onActivityStop can not be call!");
+        }
+    }
+
+  }
+
+  @Override
+  public void onActivityDestroy() {
+    WXModuleManager.onActivityDestroy(getInstanceId());
+
+    if(mRootComp != null) {
+      mRootComp.onActivityDestroy();
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely, onActivityDestroy can not be call!");
+        }
+    }
+    this.mTimeCalculator.println();
+    destroy();
+  }
+
+  @Override
+  public boolean onActivityBack() {
+
+    WXModuleManager.onActivityBack(getInstanceId());
+
+    if(mRootComp != null) {
+      return mRootComp.onActivityBack();
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely, onActivityBack can not be call!");
+        }
+    }
+
+    return false;
+  }
+
+  public boolean onSupportNavigateUp() {
+    if (mWXActionbarHandlers != null) {
+      for (ActionBarHandler handler : mWXActionbarHandlers) {
+        if (handler.onSupportNavigateUp()) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public boolean onBackPressed() {
+    if(mWXBackPressedHandlers != null) {
+      for (OnBackPressedHandler handler : mWXBackPressedHandlers) {
+        if(handler.onBackPressed()) {
+          return true;
+        }
+      }
+    }
+
+    WXComponent comp = getRootComponent();
+    if(comp != null) {
+      WXEvent events= comp.getEvents();
+      boolean hasNativeBackHook = events.contains(Constants.Event.NATIVE_BACK);
+      if (hasNativeBackHook) {
+        EventResult result = comp.fireEventWait(Constants.Event.NATIVE_BACK, null);
+        if (WXUtils.getBoolean(result.getResult(), false)) {
+          return true;
+        }
+      }
+
+      boolean hasBackPressed = events.contains(Constants.Event.CLICKBACKITEM);
+      if (hasBackPressed) {
+        fireEvent(comp.getRef(), Constants.Event.CLICKBACKITEM,null, null);
+      }
+      return hasBackPressed;
+    }
+    return false;
+  }
+
+  public void onActivityResult(int requestCode, int resultCode, Intent data){
+    WXModuleManager.onActivityResult(getInstanceId(),requestCode,resultCode,data);
+
+    if(mRootComp != null) {
+      mRootComp.onActivityResult(requestCode,resultCode,data);
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("Warning :Component tree has not build completely, onActivityResult can not be call!");
+        }
+    }
+
+
+    if (mWXOnActivityResultHandlers != null && !mWXOnActivityResultHandlers.isEmpty()) {
+      for (OnActivityResultHandler onActivityResultHandler : mWXOnActivityResultHandlers) {
+        if (onActivityResultHandler.onActivityResult(requestCode, resultCode, data)) {
+          break;
+        }
+      }
+    }
+
+  }
+
+
+  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+
+    WXModuleManager.onRequestPermissionsResult(getInstanceId(),requestCode,permissions,grantResults);
+
+    if(mRootComp != null) {
+       mRootComp.onRequestPermissionsResult(requestCode,permissions,grantResults);
+    }else{
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w(
+                "Warning :Component tree has not build completely, onRequestPermissionsResult can not be call!");
+        }
+    }
+  }
+
+  /********************************
+   *  end hook Activity life cycle callback
+   ********************************************************/
+
+  public void onViewDisappear(){
+    isViewDisAppear = false;
+    mApmForInstance.onDisAppear();
+    WXComponent comp = getRootComponent();
+    if(comp != null) {
+      fireEvent(comp.getRef(), Constants.Event.VIEWDISAPPEAR, null, null);
+      //call disappear of nested instances
+      for(OnInstanceVisibleListener instance:mVisibleListeners){
+        instance.onDisappear();
+      }
+    }
+  }
+
+  public boolean isViewDisAppear(){
+    return isViewDisAppear;
+  }
+
+  public void onViewAppear(){
+    isViewDisAppear = true;
+    mApmForInstance.onAppear();
+    WXComponent comp = getRootComponent();
+    if(comp != null) {
+      fireEvent( comp.getRef(), Constants.Event.VIEWAPPEAR,null, null);
+      for(OnInstanceVisibleListener instance:mVisibleListeners){
+        instance.onAppear();
+      }
+    }
+  }
+
+
+  public void onCreateFinish() {
+    if(mHasCreateFinish){
+      return;
+    }
+    if (mContext != null) {
+      onViewAppear();
+      View wxView= mRenderContainer;
+      if(mRenderListener != null) {
+        mRenderListener.onViewCreated(WXSDKInstance.this, wxView);
+      }
+      if (mStatisticsListener != null) {
+        mStatisticsListener.onFirstView();
+      }
+    }
+  }
+
+  /**
+   * call back when update finish
+   */
+  public void onUpdateFinish() {
+    if (WXEnvironment.isApkDebugable()){
+      WXLogUtils.d("Instance onUpdateSuccess");
+    }
+  }
+
+
+  public void runOnUiThread(Runnable action) {
+    WXSDKManager.getInstance().postOnUiThread(action, 0);
+  }
+
+  public void onRenderSuccess(final int width, final int height) {
+    isRenderSuccess = true;
+    if (!isNewFsEnd){
+      getApmForInstance().arriveNewFsRenderTime();
+    }
+    if (!getApmForInstance().stageMap.containsKey(WXInstanceApm.KEY_PAGE_STAGES_INTERACTION)){
+      getApmForInstance().arriveInteraction(getRootComponent());
+    }
+
+    long time = System.currentTimeMillis() - mRenderStartTime;
+    long[] renderFinishTime = WXBridgeManager.getInstance().getRenderFinishTime(getInstanceId());
+
+    mWXPerformance.callBridgeTime = renderFinishTime[0];
+    mWXPerformance.cssLayoutTime = renderFinishTime[1];
+    mWXPerformance.parseJsonTime = renderFinishTime[2];
+
+    mWXPerformance.totalTime = time;
+    if(mWXPerformance.screenRenderTime<0.001){
+      mWXPerformance.screenRenderTime =  time;
+    }
+
+    if (mRenderListener != null && mContext != null) {
+      mRenderListener.onRenderSuccess(WXSDKInstance.this, width, height);
+      if (mUserTrackAdapter != null) {
+        WXPerformance performance=new WXPerformance(mInstanceId);
+        performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode();
+        performance.args=getBundleUrl();
+        mUserTrackAdapter.commit(mContext,null,IWXUserTrackAdapter.JS_BRIDGE,performance,getUserTrackParams());
+      }
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d(WXLogUtils.WEEX_PERF_TAG, mWXPerformance.toString());
+      }
+    }
+    if(WXEnvironment.isPerf()){
+      WXLogUtils.e("weex_perf",mWXPerformance.getPerfData());
+    }
+  }
+
+  public void onRefreshSuccess(final int width, final int height) {
+    if (mRenderListener != null && mContext != null) {
+      mRenderListener.onRefreshSuccess(WXSDKInstance.this, width, height);
+    }
+  }
+
+  public void onChangeElement(WXComponent component, boolean isOutOfScreen) {
+
+    if (isDestroy()  || null == mRenderContainer || mWXPerformance == null ){
+      return;
+    }
+    if (null == component || component.isIgnoreInteraction){
+        return;
+    }
+
+    if (mRenderContainer.hasConsumeEvent()) {
+      return;
+    }
+
+    long lastElementChangeTime = System.currentTimeMillis();
+
+    long lazyLoadTime;
+
+    if (mHasCreateFinish){
+      lazyLoadTime = lastElementChangeTime - mWXPerformance.renderTimeOrigin;
+      if (lazyLoadTime > 8000) {
+        //force record detail performance data
+        return;
+      }
+    }
+
+    if (component.mIsAddElementToTree) {
+      getWXPerformance().localInteractionViewAddCount++;
+      if (!isOutOfScreen)
+        getWXPerformance().interactionViewAddLimitCount++;
+      component.mIsAddElementToTree = false;
+    }
+
+    if (!isOutOfScreen) {
+      mApmForInstance.arriveInteraction(component);
+    }
+  }
+
+  public void onRenderError(final String errCode, final String msg) {
+    WXStateRecord.getInstance().recordException(getInstanceId(),"onRenderError,"+errCode+","+msg);
+    if (mRenderListener != null && mContext != null) {
+      WXLogUtils.e("onRenderError "+errCode +","+msg);
+      runOnUiThread(new Runnable() {
+
+        @Override
+        public void run() {
+          if (mRenderListener != null && mContext != null) {
+            mRenderListener.onException(WXSDKInstance.this, errCode, msg);
+          }
+        }
+      });
+    }
+  }
+
+  public void onJSException(final String errCode, final String function, final String exception) {
+    WXStateRecord.getInstance().recordException(getInstanceId(),"onJSException,"+errCode+","+function+"|"+exception);
+    hasException = true;
+    if (mRenderListener != null && mContext != null) {
+      WXLogUtils.e("onJSException "+errCode +","+exception);
+      runOnUiThread(new Runnable() {
+
+        @Override
+        public void run() {
+          if (mRenderListener != null && mContext != null) {
+            StringBuilder builder = new StringBuilder();
+            builder.append(function);
+            builder.append(exception);
+            mRenderListener.onException(WXSDKInstance.this, errCode, builder.toString());
+          }
+        }
+      });
+    }
+  }
+
+
+  @Override
+  public final void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int
+          oldTop, int oldRight, int oldBottom) {
+    if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
+      onLayoutChange(v);
+    }
+  }
+
+  /**
+   * Subclass should override this method to get notifications of layout change of GodView.
+   * @param godView the godView.
+   */
+  public void onLayoutChange(View godView) {
+
+  }
+
+  private boolean mCreateInstance =true;
+  public void firstScreenCreateInstanceTime(long time) {
+    if(mCreateInstance) {
+      mWXPerformance.firstScreenJSFExecuteTime = time -mRenderStartTime;
+      mCreateInstance =false;
+    }
+  }
+
+  public void callJsTime(final long time){
+    if (!mEnd){
+      mWXPerformance.fsCallJsTotalTime+=time;
+      mWXPerformance.fsCallJsTotalNum++;
+    }
+  }
+
+  public void onComponentCreate(WXComponent component,long createTime) {
+      mWXPerformance.mActionAddElementCount++;
+      mWXPerformance.mActionAddElementSumTime += createTime;
+      if (!mEnd){
+        mWXPerformance.fsComponentCreateTime+=createTime;
+        mWXPerformance.fsComponentCount++;
+      }
+      mWXPerformance.componentCount++;
+      mWXPerformance.componentCreateTime+=createTime;
+  }
+
+  public void callActionAddElementTime(long time) {
+      mWXPerformance.mActionAddElementSumTime += time;
+  }
+
+  public void onOldFsRenderTimeLogic(){
+      if (mEnd){
+        return;
+      }
+      mEnd = true;
+      if (mStatisticsListener != null && mContext != null) {
+        runOnUiThread(new Runnable() {
+        @Override
+        public void run() {
+            if (mStatisticsListener != null && mContext != null) {
+              Trace.beginSection("onFirstScreen");
+              mStatisticsListener.onFirstScreen();
+              Trace.endSection();
+            }
+          }
+        });
+      }
+      mApmForInstance.arriveFSRenderTime();
+      mWXPerformance.fsRenderTime = System.currentTimeMillis();
+      mWXPerformance.screenRenderTime = System.currentTimeMillis() - mRenderStartTime;
+  }
+
+  public WXSDKInstance getParentInstance() {
+    return mParentInstance;
+  }
+
+  public void setParentInstance(WXSDKInstance mParentInstance) {
+    this.mParentInstance = mParentInstance;
+  }
+
+  private void destroyView(View rootView) {
+    try {
+      if (rootView instanceof ViewGroup) {
+        ViewGroup cViewGroup = ((ViewGroup) rootView);
+        for (int index = 0; index < cViewGroup.getChildCount(); index++) {
+          destroyView(cViewGroup.getChildAt(index));
+        }
+
+        cViewGroup.removeViews(0, ((ViewGroup) rootView).getChildCount());
+        // Ensure that the viewgroup's status to be normal
+        WXReflectionUtils.setValue(rootView, "mChildrenCount", 0);
+
+      }
+      if(rootView instanceof Destroyable){
+        ((Destroyable)rootView).destroy();
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("WXSDKInstance destroyView Exception: ", e);
+    }
+  }
+
+  public synchronized void destroy() {
+    if(!isDestroy()) {
+      if(mParentInstance != null){
+         mParentInstance = null;
+      }
+      mApmForInstance.onEnd();
+
+
+      if(mRendered) {
+        WXSDKManager.getInstance().destroyInstance(mInstanceId);
+      }
+
+      try {
+        if (mGlobalEventReceiver != null) {
+          getContext().unregisterReceiver(mGlobalEventReceiver);
+          mGlobalEventReceiver = null;
+        }
+      }catch (IllegalArgumentException e){
+        WXLogUtils.w(WXLogUtils.getStackTrace(e));
+      }
+
+      if (mRootComp != null) {
+        mRootComp.destroy();
+        mRootComp = null;
+      }
+
+      if(mRenderContainer != null){
+        destroyView(mRenderContainer);
+      }
+
+
+      if (mGlobalEvents != null) {
+        mGlobalEvents.clear();
+      }
+
+      if (mComponentObserver != null) {
+        mComponentObserver = null;
+      }
+
+      if (mLayerOverFlowListeners != null) {
+        mLayerOverFlowListeners.clear();
+      }
+
+      if(mWXOnActivityResultHandlers != null && !mWXOnActivityResultHandlers.isEmpty()) {
+        mWXOnActivityResultHandlers.clear();
+      }
+
+      if(mWXBackPressedHandlers != null && !mWXBackPressedHandlers.isEmpty()) {
+        mWXBackPressedHandlers.clear();
+      }
+
+      if(mWXActionbarHandlers != null && !mWXActionbarHandlers.isEmpty()) {
+        mWXActionbarHandlers.clear();
+      }
+
+      getFlatUIContext().destroy();
+      mFlatGUIContext = null;
+      mInstanceOnFireEventInterceptorList = null;
+      mWXScrollListeners = null;
+      mWXActionbarHandlers = null;
+      mWXBackPressedHandlers = null;
+      mRenderContainer = null;
+      mNestedInstanceInterceptor = null;
+      mUserTrackAdapter = null;
+      mScrollView = null;
+      mContext = null;
+      mRenderListener = null;
+      isDestroy = true;
+      mStatisticsListener = null;
+      if(responseHeaders != null){
+        responseHeaders.clear();
+      }
+      if(templateRef != null){
+        templateRef = null;
+      }
+      if (null != mContentBoxMeasurements) {
+        mContentBoxMeasurements.clear();
+      }
+      mWXPerformance.afterInstanceDestroy(mInstanceId);
+
+      WXBridgeManager.getInstance().post(new Runnable() {
+        @Override
+        public void run() {
+          WXBridgeManager.getInstance().onInstanceClose(getInstanceId());
+          inactiveAddElementAction.clear();
+        }
+      });
+
+      //when report error in @WXExceptionUtils
+      // instance may had destroy and remove,
+      // so we delay remove from allInstanceMap
+      WXBridgeManager.getInstance().postDelay(new Runnable() {
+        @Override
+        public void run() {
+          WXSDKManager.getInstance().getAllInstanceMap().remove(mInstanceId);
+        }
+      },1000);
+    }
+  }
+
+  public boolean isDestroy(){
+    return isDestroy;
+  }
+
+  /**
+   * @return If you use render () the return value may be empty
+   */
+  public @Nullable String getBundleUrl() {
+    return mBundleUrl;
+  }
+
+  public View getRootView() {
+    if (mRootComp == null)
+      return null;
+    return mRootComp.getRealView();
+  }
+
+  public View getContainerView() {
+    return mRenderContainer;
+  }
+
+  @Deprecated
+  public void setBundleUrl(String url){
+    mBundleUrl = url;
+    if(WXSDKManager.getInstance().getValidateProcessor()!=null) {
+      mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl);
+    }
+  }
+
+  public void onRootCreated(WXComponent root) {
+    this.mRootComp = root;
+    this.mRootComp.mDeepInComponentTree =1;
+    mRenderContainer.addView(root.getHostView());
+
+
+    setSize(mRenderContainer.getWidth(),mRenderContainer.getHeight());
+  }
+
+  /**
+   * Move fixed view to container ,except it's already moved.
+   * @param fixedChild
+   */
+  public void moveFixedView(View fixedChild){
+    if(mRenderContainer != null) {
+      ViewGroup parent;
+      if((parent = (ViewGroup) fixedChild.getParent()) != null){
+        if (parent != mRenderContainer) {
+          parent.removeView(fixedChild);
+          mRenderContainer.addView(fixedChild);
+        }
+      }else{
+        mRenderContainer.addView(fixedChild);
+      }
+    }
+  }
+
+  public void removeFixedView(View fixedChild){
+    if(mRenderContainer != null) {
+      mRenderContainer.removeView(fixedChild);
+    }
+  }
+
+  public int getRenderContainerPaddingLeft() {
+    if(mRenderContainer != null) {
+      return mRenderContainer.getPaddingLeft();
+    }
+    return 0;
+  }
+
+  public int getRenderContainerPaddingRight() {
+    if(mRenderContainer != null) {
+      return mRenderContainer.getPaddingRight();
+    }
+    return 0;
+  }
+
+  public int getRenderContainerPaddingTop() {
+    if(mRenderContainer != null) {
+      return mRenderContainer.getPaddingTop();
+    }
+    return 0;
+  }
+
+  public synchronized List<OnWXScrollListener> getWXScrollListeners() {
+    return mWXScrollListeners;
+  }
+
+  public synchronized void registerOnWXScrollListener(OnWXScrollListener wxScrollListener) {
+    if(mWXScrollListeners==null){
+      mWXScrollListeners=new ArrayList<>();
+    }
+    mWXScrollListeners.add(wxScrollListener);
+  }
+
+  public synchronized void registerActionbarHandler(ActionBarHandler actionBarHandler) {
+    if(actionBarHandler == null) {
+      return;
+    }
+    if(mWXActionbarHandlers == null) {
+      mWXActionbarHandlers = new ArrayList<>();
+    }
+
+    mWXActionbarHandlers.add(actionBarHandler);
+  }
+
+  public synchronized void unRegisterActionbarHandler(ActionBarHandler actionBarHandler) {
+    if(mWXActionbarHandlers != null && actionBarHandler != null) {
+      mWXActionbarHandlers.remove(actionBarHandler);
+    }
+  }
+
+  public synchronized void unRegisterOnActivityResultHandler(OnActivityResultHandler onActivityResultHandler) {
+    if(mWXOnActivityResultHandlers != null && onActivityResultHandler != null) {
+      mWXOnActivityResultHandlers.remove(onActivityResultHandler);
+    }
+  }
+
+  public synchronized void registerOnActivityResultHandler(OnActivityResultHandler onActivityResultHandler) {
+    if(onActivityResultHandler == null) {
+      return;
+    }
+
+    if(mWXOnActivityResultHandlers == null) {
+      mWXOnActivityResultHandlers = new ArrayList<>();
+    }
+    mWXOnActivityResultHandlers.add(onActivityResultHandler);
+  }
+
+
+  public synchronized void registerBackPressedHandler(OnBackPressedHandler backPressedHandler) {
+    if(backPressedHandler == null) {
+      return;
+    }
+
+    if(mWXBackPressedHandlers == null) {
+      mWXBackPressedHandlers = new ArrayList<>();
+    }
+
+    mWXBackPressedHandlers.add(backPressedHandler);
+  }
+
+  public synchronized void unRegisterBackPressedHandler(OnBackPressedHandler backPressedHandler) {
+    if(mWXBackPressedHandlers != null && backPressedHandler != null) {
+      mWXBackPressedHandlers.remove(backPressedHandler);
+    }
+  }
+
+  static int sScreenHeight = -1;
+  public void setSize(int width, int height) {
+    if (width > 0 && height > 0 & !isDestroy && mRendered && mRenderContainer != null) {
+        if (sScreenHeight < 0){
+            sScreenHeight = WXViewUtils.getScreenHeight(getContext());
+        }
+        if (sScreenHeight>0){
+            double screenRatio = (double)height/(double)sScreenHeight *100;
+            if(screenRatio>100){
+              screenRatio =100;
+            }
+            getApmForInstance().addStats(WXInstanceApm.KEY_PAGE_STATS_BODY_RATIO,screenRatio);
+        }
+      ViewGroup.LayoutParams layoutParams = mRenderContainer.getLayoutParams();
+      if (layoutParams != null) {
+        final float realWidth = width;
+        final float realHeight = height;
+        if (mRenderContainer.getWidth() != width || mRenderContainer.getHeight() != height) {
+          layoutParams.width = width;
+          layoutParams.height = height;
+          mRenderContainer.setLayoutParams(layoutParams);
+        }
+
+        if (mRootComp != null && layoutParams != null) {
+          final boolean isWidthWrapContent = layoutParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
+          final boolean isHeightWrapContent = layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT;
+
+          WXBridgeManager.getInstance().post(new Runnable() {
+            @Override
+            public void run() {
+              WXBridgeManager.getInstance().setDefaultRootSize(getInstanceId(), realWidth, realHeight, isWidthWrapContent,
+                      isHeightWrapContent);
+            }
+          });
+        }
+      }
+    }
+  }
+
+  /*Global Event*/
+  private HashMap<String, List<String>> mGlobalEvents = new HashMap<>();
+
+  public void fireGlobalEventCallback(String eventName, Map<String,Object> params){
+    List<String> callbacks=mGlobalEvents.get(eventName);
+    if(callbacks!=null){
+      for(String callback:callbacks){
+        WXSDKManager.getInstance().callback(mInstanceId,callback,params,true);
+      }
+    }
+  }
+
+  /**
+   * Fire event callback on a element.
+   * @param elementRef
+   * @param type
+   * @param data
+   * @param domChanges
+   */
+  public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges, List<Object> eventArgs){
+    fireEvent(elementRef, type, data, domChanges, eventArgs, null);
+  }
+
+  public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges, List<Object> eventArgs, EventResult callback) {
+    onInterceptInstanceEvent(getInstanceId(), elementRef, type, data, domChanges);
+    if (null != mWXPerformance && mWXPerformance.fsCallEventTotalNum<Integer.MAX_VALUE){
+      mWXPerformance.fsCallEventTotalNum++;
+    }
+    mApmForInstance.updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_EVENT_NUM,1);
+    WXBridgeManager.getInstance().fireEventOnNode(getInstanceId(),elementRef,type,data,domChanges, eventArgs, callback);
+  }
+
+
+  /**
+   * Fire event callback on a element.
+   * @param elementRef
+   * @param type
+   * @param data
+   * @param domChanges
+   */
+  public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges){
+    fireEvent(elementRef, type, data, domChanges, null);
+  }
+
+  public void fireEvent(String elementRef,final String type, final Map<String, Object> data){
+    fireEvent(elementRef,type,data,null);
+  }
+
+  public void fireEvent(String ref, String type){
+    fireEvent(ref,type,new HashMap<String, Object>());
+  }
+
+  protected void addEventListener(String eventName, String callback) {
+    if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) {
+      return;
+    }
+    List<String> callbacks = mGlobalEvents.get(eventName);
+    if (callbacks == null) {
+      callbacks = new ArrayList<>();
+      mGlobalEvents.put(eventName, callbacks);
+    }
+    callbacks.add(callback);
+  }
+  protected void removeEventListener(String eventName, String callback) {
+    if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) {
+      return;
+    }
+    List<String> callbacks = mGlobalEvents.get(eventName);
+    if (callbacks != null) {
+      callbacks.remove(callback);
+    }
+  }
+
+  protected void removeEventListener(String eventName) {
+    if (TextUtils.isEmpty(eventName)) {
+      return;
+    }
+    mGlobalEvents.remove(eventName);
+  }
+
+  /**
+   * Notifies WEEX that this event has occurred
+   * @param eventName WEEX register event
+   * @param module Events occur in this Module
+   * @param params The parameters to be notified to WEEX are required
+   */
+  public void fireModuleEvent(String eventName, WXModule module,Map<String, Object> params) {
+    if (TextUtils.isEmpty(eventName) || module == null) {
+      return;
+    }
+
+    Map<String, Object> event = new HashMap<>();
+    event.put("type", eventName);
+    event.put("module", module.getModuleName());
+    event.put("data", params);
+
+    List<String> callbacks = module.getEventCallbacks(eventName);
+    if (callbacks != null) {
+      for (String callback : callbacks) {
+        SimpleJSCallback jsCallback = new SimpleJSCallback(mInstanceId, callback);
+        if (module.isOnce(callback)) {
+          jsCallback.invoke(event);
+        } else {
+          jsCallback.invokeAndKeepAlive(event);
+        }
+      }
+    }
+  }
+
+  /**
+   * Check whether the current module registered the event
+   * @param eventName EventName register in weex
+   * @param module Events occur in this Module
+   * @return  register->true
+   */
+  public boolean checkModuleEventRegistered(String eventName,WXModule module) {
+    if (module != null) {
+      List<String> events = module.getEventCallbacks(eventName);
+      if (events != null && events.size() > 0) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public WXPerformance getWXPerformance(){
+    return mWXPerformance;
+  }
+
+  public WXInstanceApm getApmForInstance() {
+    return mApmForInstance;
+  }
+
+  public Map<String, Serializable> getUserTrackParams() {
+    return mUserTrackParams;
+  }
+
+  public void addUserTrackParameter(String key,Serializable value){
+    if(this.mUserTrackParams == null){
+      this.mUserTrackParams = new ConcurrentHashMap<>();
+    }
+    mUserTrackParams.put(key,value);
+  }
+
+  public void clearUserTrackParameters(){
+    if(this.mUserTrackParams != null){
+      this.mUserTrackParams.clear();
+    }
+  }
+
+  public void removeUserTrackParameter(String key){
+    if(this.mUserTrackParams != null){
+      this.mUserTrackParams.remove(key);
+    }
+  }
+
+  public int getMaxDeepLayer() {
+    return mMaxDeepLayer;
+  }
+
+  public void setMaxDeepLayer(int maxDeepLayer) {
+    mMaxDeepLayer = maxDeepLayer;
+    mApmForInstance.updateMaxStats(WXInstanceApm.KEY_PAGE_STATS_MAX_DEEP_VIEW,maxDeepLayer);
+  }
+
+  public void setMaxDomDeep(int maxDomDeep){
+    mApmForInstance.updateMaxStats(WXInstanceApm.KEY_PAGE_STATS_MAX_DEEP_DOM,maxDomDeep);
+    if (null == mWXPerformance){
+      return;
+    }
+    if (mWXPerformance.maxDeepVDomLayer <= maxDomDeep){
+      mWXPerformance.maxDeepVDomLayer = maxDomDeep;
+    }
+  }
+
+  public void onHttpStart(){
+    if (!mEnd){
+      mWXPerformance.fsRequestNum++;
+    }
+  }
+
+  /**
+   * return md5, and bytes length
+   * */
+  public String getTemplateInfo() {
+    String template = getTemplate();
+    if(template == null){
+      return " template md5 null ,httpHeader:" + JSONObject.toJSONString(responseHeaders);
+    }
+    if(TextUtils.isEmpty(template)){
+      return " template md5  length 0 ,httpHeader" + JSONObject.toJSONString(responseHeaders);
+    }
+    try {
+      byte[] bts = template.getBytes("UTF-8");
+      String sourceMD5 = WXFileUtils.md5(bts);
+      String sourceBase64MD5 = WXFileUtils.base64Md5(bts);
+      ArrayList<String> sourceMD5List = new ArrayList<>();
+      ArrayList<String> sourceBase64MD5List = new ArrayList<>();
+      sourceMD5List.add(sourceMD5);
+      sourceBase64MD5List.add(sourceBase64MD5);
+      responseHeaders.put("templateSourceMD5", sourceMD5List);
+      responseHeaders.put(SOURCE_TEMPLATE_BASE64_MD5, sourceBase64MD5List);
+      return " template md5 " + sourceMD5 + " length " +   bts.length
+              + " base64 md5 " + sourceBase64MD5
+              + " response header " + JSONObject.toJSONString(responseHeaders);
+    } catch (Exception e) {
+      return "template md5 getBytes error";
+    }
+
+  }
+
+  /**
+   * check template header md5 match with header  content-md5
+   * */
+  public boolean isContentMd5Match(){
+    if(responseHeaders == null){
+      return true;
+    }
+    List<String> contentMD5s = responseHeaders.get("Content-Md5");
+    if(contentMD5s == null){
+      contentMD5s  = responseHeaders.get("content-md5");
+    }
+    if(contentMD5s == null || contentMD5s.size() <= 0){
+      return true;
+    }
+    String md5 = contentMD5s.get(0);
+
+    List<String> sourceBase64Md5 = responseHeaders.get(SOURCE_TEMPLATE_BASE64_MD5);
+    if(sourceBase64Md5 == null){
+      getTemplateInfo();
+      sourceBase64Md5 = responseHeaders.get(SOURCE_TEMPLATE_BASE64_MD5);
+    }
+    if(sourceBase64Md5 == null || sourceBase64Md5.size() == 0){
+      return  true;
+    }
+    return  md5.equals(sourceBase64Md5.get(0));
+  }
+
+  public String getTemplate() {
+    if(templateRef == null){
+      return  null;
+    }
+    return templateRef.get();
+  }
+
+  public void setTemplate(String template) {
+    this.templateRef = new WeakReference<String>(template);
+  }
+
+  public interface NestedInstanceInterceptor {
+    void onCreateNestInstance(WXSDKInstance instance, NestedContainer container);
+  }
+
+  public void OnVSync() {
+    boolean forceLayout = WXBridgeManager.getInstance().notifyLayout(getInstanceId());
+    if(forceLayout) {
+      WXBridgeManager.getInstance().post(new Runnable() {
+        @Override
+        public void run() {
+          WXBridgeManager.getInstance().forceLayout(getInstanceId());
+        }
+      });
+    }
+  }
+
+  public void addContentBoxMeasurement(long renderObjectPtr, ContentBoxMeasurement contentBoxMeasurement) {
+    mContentBoxMeasurements.put(renderObjectPtr, contentBoxMeasurement);
+  }
+
+  public ContentBoxMeasurement getContentBoxMeasurement(long renderObjectPtr) {
+    return mContentBoxMeasurements.get(renderObjectPtr);
+  }
+
+
+  private void onInterceptInstanceEvent(String instanceId, String elementRef, String type, Map<String, Object> data, Map<String, Object> domChanges) {
+    if(this.mInstanceOnFireEventInterceptorList == null){
+      return;
+    }
+    for(InstanceOnFireEventInterceptor instanceOnFireEventInterceptor : this.mInstanceOnFireEventInterceptorList){
+      instanceOnFireEventInterceptor.onInterceptFireEvent(instanceId, elementRef, type, data, domChanges);
+    }
+  }
+
+  public List<InstanceOnFireEventInterceptor> getInstanceOnFireEventInterceptorList(){
+    if(this.mInstanceOnFireEventInterceptorList == null){
+      this.mInstanceOnFireEventInterceptorList = new ArrayList<>();
+    }
+    return mInstanceOnFireEventInterceptorList;
+  }
+
+
+  public void addInstanceOnFireEventInterceptor(InstanceOnFireEventInterceptor instanceOnFireEventInterceptor) {
+    if(instanceOnFireEventInterceptor == null){
+      return;
+    }
+    if(!getInstanceOnFireEventInterceptorList().contains(instanceOnFireEventInterceptor)){
+      getInstanceOnFireEventInterceptorList().add(instanceOnFireEventInterceptor);
+    }
+  }
+
+  public String getRenderType() {
+    return mRenderType;
+  }
+
+  public void setRenderType(String renderType) {
+    this.mRenderType = renderType;
+  }
+
+  private static boolean isDisableSkipFrameworkInDataRender() {
+    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+    if (adapter == null) {
+      return false;
+    }
+    String result = adapter.getConfig("wxeagle", "disable_skip_framework_init", "false");
+    return "true".equals(result);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/WXSDKManager.java b/android/sdk/src/main/java/org/apache/weex/WXSDKManager.java
new file mode 100644
index 0000000..628e4cc
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WXSDKManager.java
@@ -0,0 +1,540 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.apache.weex.adapter.ClassLoaderAdapter;
+import org.apache.weex.adapter.DefaultUriAdapter;
+import org.apache.weex.adapter.DefaultWXHttpAdapter;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.adapter.ICrashInfoReporter;
+import org.apache.weex.adapter.IDrawableLoader;
+import org.apache.weex.adapter.IWXJscProcessManager;
+import org.apache.weex.adapter.ITracingAdapter;
+import org.apache.weex.adapter.IWXAccessibilityRoleAdapter;
+import org.apache.weex.adapter.IWXHttpAdapter;
+import org.apache.weex.adapter.IWXImgLoaderAdapter;
+import org.apache.weex.adapter.IWXJSExceptionAdapter;
+import org.apache.weex.adapter.IWXJsFileLoaderAdapter;
+import org.apache.weex.adapter.IWXSoLoaderAdapter;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.appfram.navigator.IActivityNavBarSetter;
+import org.apache.weex.appfram.navigator.INavigator;
+import org.apache.weex.appfram.storage.DefaultWXStorage;
+import org.apache.weex.appfram.storage.IWXStorageAdapter;
+import org.apache.weex.appfram.websocket.IWebSocketAdapter;
+import org.apache.weex.appfram.websocket.IWebSocketAdapterFactory;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.bridge.WXModuleManager;
+import org.apache.weex.bridge.WXValidateProcessor;
+import org.apache.weex.common.WXRefreshData;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.common.WXWorkThreadManager;
+import org.apache.weex.font.FontAdapter;
+import org.apache.weex.performance.IApmGenerator;
+import org.apache.weex.performance.IWXAnalyzer;
+import org.apache.weex.ui.WXRenderManager;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manger class for weex context.
+ */
+public class WXSDKManager {
+
+  private static volatile WXSDKManager sManager;
+  private static AtomicInteger sInstanceId = new AtomicInteger(0);
+  private final WXWorkThreadManager mWXWorkThreadManager;
+  private WXBridgeManager mBridgeManager;
+  /** package **/ WXRenderManager mWXRenderManager;
+
+  private IWXUserTrackAdapter mIWXUserTrackAdapter;
+  private IWXImgLoaderAdapter mIWXImgLoaderAdapter;
+  private IWXSoLoaderAdapter mIWXSoLoaderAdapter;
+  private IDrawableLoader mDrawableLoader;
+  private IWXHttpAdapter mIWXHttpAdapter;
+  private IActivityNavBarSetter mActivityNavBarSetter;
+  private IWXAccessibilityRoleAdapter mRoleAdapter;
+  private List<IWXAnalyzer> mWXAnalyzerList;
+  private IApmGenerator mApmGenerater;
+  private IWXJsFileLoaderAdapter mWXJsFileLoaderAdapter;
+
+  private ICrashInfoReporter mCrashInfo;
+
+  private IWXJSExceptionAdapter mIWXJSExceptionAdapter;
+
+  private IWXConfigAdapter mConfigAdapter;
+  private IWXStorageAdapter mIWXStorageAdapter;
+  private IWXStatisticsListener mStatisticsListener;
+  private URIAdapter mURIAdapter;
+  private ClassLoaderAdapter mClassLoaderAdapter;
+  private IWebSocketAdapterFactory mIWebSocketAdapterFactory;
+  private ITracingAdapter mTracingAdapter;
+  private WXValidateProcessor mWXValidateProcessor;
+  private IWXJscProcessManager mWXJscProcessManager;
+  // Tell weexv8 to initialize v8, default is true.
+  private boolean mNeedInitV8 = true;
+
+  //add when instance create,rm when instance destroy, not like WXRenderManager
+  private Map<String,WXSDKInstance> mAllInstanceMap;
+
+  private List<InstanceLifeCycleCallbacks> mLifeCycleCallbacks;
+
+  private static final int DEFAULT_VIEWPORT_WIDTH = 750;
+
+  private WXSDKManager() {
+    this(new WXRenderManager());
+  }
+
+  private WXSDKManager(WXRenderManager renderManager) {
+    mWXRenderManager = renderManager;
+    mBridgeManager = WXBridgeManager.getInstance();
+    mWXWorkThreadManager = new WXWorkThreadManager();
+    mWXAnalyzerList = new CopyOnWriteArrayList<>();
+    mAllInstanceMap = new HashMap<>();
+  }
+
+  /**
+   * Used in junit test
+   */
+  static void initInstance(WXRenderManager renderManager){
+    sManager = new WXSDKManager(renderManager);
+  }
+
+  public void registerStatisticsListener(IWXStatisticsListener listener) {
+    mStatisticsListener = listener;
+  }
+
+  public IWXStatisticsListener getWXStatisticsListener() {
+    return mStatisticsListener;
+  }
+
+  public void onSDKEngineInitialize() {
+    if (mStatisticsListener != null) {
+      mStatisticsListener.onSDKEngineInitialize();
+    }
+  }
+
+  public void setNeedInitV8(boolean need) {
+    mNeedInitV8 = need;
+  }
+
+  public boolean needInitV8() {
+    return mNeedInitV8;
+  }
+
+  public void takeJSHeapSnapshot(String path) {
+    File file = new File(path);
+    if (!file.exists()) {
+      if (!file.mkdir()) {
+        return;
+      }
+    }
+
+    String name = String.valueOf(sInstanceId.get());
+    String filename = path;
+
+    if (!path.endsWith(File.separator)) {
+      filename += File.separator;
+    }
+    filename += name;
+    filename += ".heapsnapshot";
+
+    mBridgeManager.takeJSHeapSnapshot(filename);
+  }
+
+  public static WXSDKManager getInstance() {
+    if (sManager == null) {
+      synchronized (WXSDKManager.class) {
+        if(sManager == null) {
+          sManager = new WXSDKManager();
+        }
+      }
+    }
+    return sManager;
+  }
+
+  public static int getInstanceViewPortWidth(String instanceId){
+    WXSDKInstance instance = getInstance().getSDKInstance(instanceId);
+    if (instance == null) {
+      return DEFAULT_VIEWPORT_WIDTH;
+    }
+    return instance.getInstanceViewPortWidth();
+  }
+
+  static void setInstance(WXSDKManager manager){
+    sManager = manager;
+  }
+
+  public IActivityNavBarSetter getActivityNavBarSetter() {
+    return mActivityNavBarSetter;
+  }
+
+  public void setActivityNavBarSetter(IActivityNavBarSetter mActivityNavBarSetter) {
+    this.mActivityNavBarSetter = mActivityNavBarSetter;
+  }
+
+  public void restartBridge() {
+    mBridgeManager.restart();
+  }
+
+  public WXBridgeManager getWXBridgeManager() {
+    return mBridgeManager;
+  }
+
+  public WXRenderManager getWXRenderManager() {
+    return mWXRenderManager;
+  }
+  public IWXJscProcessManager getWXJscProcessManager() {
+    return mWXJscProcessManager;
+  }
+  public WXWorkThreadManager getWXWorkThreadManager() {
+    return mWXWorkThreadManager;
+  }
+
+  public void setWxConfigAdapter(IWXConfigAdapter mConfigAdapter) {
+    this.mConfigAdapter = mConfigAdapter;
+  }
+
+  public IWXConfigAdapter getWxConfigAdapter() {
+    return mConfigAdapter;
+  }
+
+  public @Nullable WXSDKInstance getSDKInstance(String instanceId) {
+    return instanceId == null? null : mWXRenderManager.getWXSDKInstance(instanceId);
+  }
+
+  public void postOnUiThread(Runnable runnable, long delayMillis) {
+    mWXRenderManager.postOnUiThread(WXThread.secure(runnable), delayMillis);
+  }
+  public Map<String, WXSDKInstance> getAllInstanceMap() {
+    return mAllInstanceMap;
+  }
+
+  public void destroy() {
+    if (mWXWorkThreadManager != null) {
+      mWXWorkThreadManager.destroy();
+    }
+    mAllInstanceMap.clear();
+  }
+
+  @Deprecated
+  public void callback(String instanceId, String funcId, Map<String, Object> data) {
+    mBridgeManager.callback(instanceId, funcId, data);
+  }
+
+  @Deprecated
+  public void callback(String instanceId, String funcId, Map<String, Object> data,boolean keepAlive) {
+    mBridgeManager.callback(instanceId, funcId, data,keepAlive);
+  }
+
+  public void initScriptsFramework(String framework) {
+    mBridgeManager.initScriptsFramework(framework);
+  }
+
+  public void registerComponents(List<Map<String, Object>> components) {
+    mBridgeManager.registerComponents(components);
+  }
+
+  public void registerModules(Map<String, Object> modules) {
+    mBridgeManager.registerModules(modules);
+  }
+
+  /**
+   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
+   */
+  @Deprecated
+  public void fireEvent(final String instanceId, String ref, String type) {
+    fireEvent(instanceId, ref, type, new HashMap<String, Object>());
+  }
+
+  /**
+   * FireEvent back to JS
+   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
+   */
+  @Deprecated
+  public void fireEvent(final String instanceId, String ref, String type, Map<String, Object> params){
+    fireEvent(instanceId,ref,type,params,null);
+  }
+
+  /**
+   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
+   **/
+  @Deprecated
+  public void fireEvent(final String instanceId, String ref, String type, Map<String, Object> params,Map<String,Object> domChanges) {
+    if (WXEnvironment.isApkDebugable() && Looper.getMainLooper().getThread().getId() != Thread.currentThread().getId()) {
+      throw new WXRuntimeException("[WXSDKManager]  fireEvent error");
+    }
+    mBridgeManager.fireEventOnNode(instanceId, ref, type, params,domChanges);
+  }
+
+  void createInstance(WXSDKInstance instance, Script code, Map<String, Object> options, String jsonInitData) {
+    mWXRenderManager.registerInstance(instance);
+    mBridgeManager.createInstance(instance.getInstanceId(), code, options, jsonInitData);
+    if (mLifeCycleCallbacks != null) {
+      for (InstanceLifeCycleCallbacks callbacks : mLifeCycleCallbacks) {
+        callbacks.onInstanceCreated(instance.getInstanceId());
+      }
+    }
+  }
+
+  void refreshInstance(String instanceId, WXRefreshData jsonData) {
+    mBridgeManager.refreshInstance(instanceId, jsonData);
+  }
+
+  void destroyInstance(String instanceId) {
+    setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,"");
+    if (TextUtils.isEmpty(instanceId)) {
+      return;
+    }
+    if (!WXUtils.isUiThread()) {
+      throw new WXRuntimeException("[WXSDKManager] destroyInstance error");
+    }
+    if (mLifeCycleCallbacks != null) {
+      for (InstanceLifeCycleCallbacks callbacks : mLifeCycleCallbacks) {
+        callbacks.onInstanceDestroyed(instanceId);
+      }
+    }
+    mWXRenderManager.removeRenderStatement(instanceId);
+    mBridgeManager.destroyInstance(instanceId);
+    WXModuleManager.destroyInstanceModules(instanceId);
+  }
+
+  String generateInstanceId() {
+    return String.valueOf(sInstanceId.incrementAndGet());
+  }
+
+  public IWXUserTrackAdapter getIWXUserTrackAdapter() {
+    return mIWXUserTrackAdapter;
+  }
+
+  public IWXImgLoaderAdapter getIWXImgLoaderAdapter() {
+    return mIWXImgLoaderAdapter;
+  }
+
+  public IWXJsFileLoaderAdapter getIWXJsFileLoaderAdapter() {
+    return mWXJsFileLoaderAdapter;
+  }
+
+  public IDrawableLoader getDrawableLoader() {
+    return mDrawableLoader;
+  }
+
+  public IWXJSExceptionAdapter getIWXJSExceptionAdapter() {
+    return mIWXJSExceptionAdapter;
+  }
+
+  public void setIWXJSExceptionAdapter(IWXJSExceptionAdapter IWXJSExceptionAdapter) {
+    mIWXJSExceptionAdapter = IWXJSExceptionAdapter;
+  }
+
+  public @NonNull IWXHttpAdapter getIWXHttpAdapter() {
+    if (mIWXHttpAdapter == null) {
+      mIWXHttpAdapter = new DefaultWXHttpAdapter();
+    }
+    return mIWXHttpAdapter;
+  }
+
+  public IApmGenerator getApmGenerater() {
+    return mApmGenerater;
+  }
+
+  public @NonNull URIAdapter getURIAdapter() {
+    if(mURIAdapter == null){
+      mURIAdapter = new DefaultUriAdapter();
+    }
+    return mURIAdapter;
+  }
+
+  public ClassLoaderAdapter getClassLoaderAdapter() {
+    if(mClassLoaderAdapter == null){
+      mClassLoaderAdapter = new ClassLoaderAdapter();
+    }
+    return mClassLoaderAdapter;
+  }
+
+  public IWXSoLoaderAdapter getIWXSoLoaderAdapter() {
+    return mIWXSoLoaderAdapter;
+  }
+
+  public List<IWXAnalyzer> getWXAnalyzerList(){
+    return mWXAnalyzerList;
+  }
+
+  public void addWXAnalyzer(IWXAnalyzer analyzer){
+    if (!mWXAnalyzerList.contains(analyzer)) {
+      mWXAnalyzerList.add(analyzer);
+    }
+  }
+
+  public void rmWXAnalyzer(IWXAnalyzer analyzer){
+    mWXAnalyzerList.remove(analyzer);
+  }
+
+  void setInitConfig(InitConfig config){
+    this.mIWXHttpAdapter = config.getHttpAdapter();
+    this.mIWXImgLoaderAdapter = config.getImgAdapter();
+    this.mDrawableLoader = config.getDrawableLoader();
+    this.mIWXStorageAdapter = config.getStorageAdapter();
+    this.mIWXUserTrackAdapter = config.getUtAdapter();
+    this.mURIAdapter = config.getURIAdapter();
+    this.mIWebSocketAdapterFactory = config.getWebSocketAdapterFactory();
+    this.mIWXJSExceptionAdapter = config.getJSExceptionAdapter();
+    this.mIWXSoLoaderAdapter = config.getIWXSoLoaderAdapter();
+    this.mClassLoaderAdapter = config.getClassLoaderAdapter();
+    this.mApmGenerater = config.getApmGenerater();
+    this.mWXJsFileLoaderAdapter = config.getJsFileLoaderAdapter();
+    this.mWXJscProcessManager = config.getJscProcessManager();
+  }
+
+  public IWXStorageAdapter getIWXStorageAdapter(){
+    if(mIWXStorageAdapter == null){
+      if(WXEnvironment.sApplication != null){
+        mIWXStorageAdapter = new DefaultWXStorage(WXEnvironment.sApplication);
+      }else{
+        WXLogUtils.e("WXStorageModule", "No Application context found,you should call WXSDKEngine#initialize() method in your application");
+      }
+    }
+    return mIWXStorageAdapter;
+  }
+
+  /**
+   * Weex embedders can use <code>notifyTrimMemory</code> to reduce
+   * memory at a proper time.
+   *
+   * It's not a good idea to reduce memory at any time, because
+   * memory trimming is a expense operation, and V8 needs to do
+   * a full GC and all the inline caches get to be cleared.
+   *
+   * The embedder needs to make some scheduling strategies to
+   * ensure that the embedded application is just on an idle time.
+   * If the application use the same js bundle to render pages,
+   * it's not a good idea to trim memory every time of exiting
+   * pages.
+   */
+  public void notifyTrimMemory() {
+    mBridgeManager.notifyTrimMemory();
+  }
+
+  /**
+   * Weex embedders can use <code>notifySerializeCodeCache</code> to
+   * serialize code caches if the jsfm has the alility to compile 'new Function'
+   * against js bundles on the weex native side.
+   *
+   * It's a good time to serialize a code cache after exiting a weex page.
+   * Then, the next time of entering the same weex page, V8 would compile
+   * 'new Function' against the code cache deseriazed from the js bundle.
+   */
+  public void notifySerializeCodeCache() {
+    mBridgeManager.notifySerializeCodeCache();
+  }
+
+  public @Nullable
+  IWebSocketAdapter getIWXWebSocketAdapter() {
+    if (mIWebSocketAdapterFactory != null) {
+      return mIWebSocketAdapterFactory.createWebSocketAdapter();
+    }
+    return null;
+  }
+
+  public void registerValidateProcessor(WXValidateProcessor processor){
+    this.mWXValidateProcessor = processor;
+  }
+
+  public WXValidateProcessor getValidateProcessor(){
+    return mWXValidateProcessor;
+  }
+
+
+  public void setCrashInfoReporter(ICrashInfoReporter mCrashInfo) {
+    this.mCrashInfo = mCrashInfo;
+  }
+
+  public void setCrashInfo(String key, String value) {
+    if(mCrashInfo!=null){
+      mCrashInfo.addCrashInfo(key,value);
+    }
+  }
+
+  public void setTracingAdapter(ITracingAdapter adapter) {
+    this.mTracingAdapter = adapter;
+  }
+
+  public ITracingAdapter getTracingAdapter() {
+    return mTracingAdapter;
+  }
+
+  public void registerInstanceLifeCycleCallbacks(InstanceLifeCycleCallbacks callbacks) {
+    if (mLifeCycleCallbacks == null) {
+      mLifeCycleCallbacks = new ArrayList<>();
+    }
+    mLifeCycleCallbacks.add(callbacks);
+  }
+
+  public void setAccessibilityRoleAdapter(IWXAccessibilityRoleAdapter adapter) {
+    this.mRoleAdapter = adapter;
+  }
+
+  public IWXAccessibilityRoleAdapter getAccessibilityRoleAdapter() {
+    return mRoleAdapter;
+  }
+
+  public interface InstanceLifeCycleCallbacks {
+    void onInstanceDestroyed(String instanceId);
+    void onInstanceCreated(String instanceId);
+  }
+
+  private INavigator mNavigator;
+
+  public INavigator getNavigator() {
+    return mNavigator;
+  }
+
+  public void setNavigator(INavigator mNavigator) {
+    this.mNavigator = mNavigator;
+  }
+
+
+  private FontAdapter mFontAdapter;
+
+  public FontAdapter getFontAdapter(){
+      if(mFontAdapter == null){
+        synchronized (this){
+          if(mFontAdapter == null){
+              mFontAdapter = new FontAdapter();
+          }
+        }
+      }
+      return mFontAdapter;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/WeexFrameRateControl.java b/android/sdk/src/main/java/org/apache/weex/WeexFrameRateControl.java
new file mode 100644
index 0000000..2d98862
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/WeexFrameRateControl.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex;
+
+/**
+ * Created by shiwentao on 2017/8/24.
+ */
+
+import android.annotation.SuppressLint;
+import android.os.Build;
+import android.util.Log;
+import android.view.Choreographer;
+import org.apache.weex.common.WXErrorCode;
+import java.lang.ref.WeakReference;
+
+public class WeexFrameRateControl {
+    private static final long VSYNC_FRAME = 1000 / 60;
+    private WeakReference<VSyncListener> mListener;
+    private final Choreographer mChoreographer;
+    private final Choreographer.FrameCallback mVSyncFrameCallback;
+    private final Runnable runnable;
+
+    public interface VSyncListener {
+        void OnVSync();
+    }
+
+    public WeexFrameRateControl(VSyncListener listener) {
+        mListener = new WeakReference<>(listener);
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+            mChoreographer = Choreographer.getInstance();
+            mVSyncFrameCallback = new Choreographer.FrameCallback() {
+                @SuppressLint("NewApi")
+                @Override
+                public void doFrame(long frameTimeNanos) {
+                    VSyncListener vSyncListener;
+                    if (mListener != null && (vSyncListener=mListener.get()) != null) {
+                        try {
+                            vSyncListener.OnVSync();
+                            mChoreographer.postFrameCallback(mVSyncFrameCallback);
+                        }catch (UnsatisfiedLinkError e){
+                            if(vSyncListener instanceof WXSDKInstance){
+                                ((WXSDKInstance) vSyncListener).onRenderError(
+                                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+                                    Log.getStackTraceString(e));
+                            }
+                        }
+                    }
+                }
+            };
+            runnable = null;
+        } else {
+            // For API 15 or lower
+            runnable = new Runnable() {
+                @Override
+                public void run() {
+                    VSyncListener vSyncListener;
+                    if (mListener != null && (vSyncListener = mListener.get()) != null) {
+                        try {
+                            vSyncListener.OnVSync();
+                            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(runnable, VSYNC_FRAME);
+                        }catch (UnsatisfiedLinkError e){
+                            if(vSyncListener instanceof WXSDKInstance){
+                                ((WXSDKInstance) vSyncListener).onRenderError(
+                                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+                                    Log.getStackTraceString(e));
+                            }
+                        }
+                    }
+                }
+            };
+            mChoreographer = null;
+            mVSyncFrameCallback = null;
+        }
+    }
+
+    @SuppressLint("NewApi")
+    public void start() {
+        if (mChoreographer != null) {
+            mChoreographer.postFrameCallback(mVSyncFrameCallback);
+        }
+        else if(runnable!=null){
+            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(runnable, VSYNC_FRAME);
+        }
+    }
+
+    @SuppressLint("NewApi")
+    public void stop() {
+        if (mChoreographer != null) {
+            mChoreographer.removeFrameCallback(mVSyncFrameCallback);
+        }else if(runnable!=null){
+            WXSDKManager.getInstance().getWXRenderManager().removeTask(runnable);
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/ClassLoaderAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/ClassLoaderAdapter.java
new file mode 100644
index 0000000..e141025
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/ClassLoaderAdapter.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import android.content.Context;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by furture on 2018/2/7.
+ * class loader adapter for load auto config class.
+ */
+public class ClassLoaderAdapter {
+
+    /**
+     * context is module class
+     * */
+    public Class<? extends WXModule> getModuleClass(String name, String className, Context context){
+        try {
+            return (Class<? extends WXModule>) context.getClassLoader().loadClass(className);
+        } catch (ClassNotFoundException e) {
+            throw  new RuntimeException(e);
+        }
+    }
+
+    /**
+     * context is instance context
+     */
+    public Class<? extends WXComponent> getComponentClass(String name, String className, WXSDKInstance instance) {
+        try {
+            return (Class<? extends WXComponent>) instance.getContext().getClassLoader().loadClass(className);
+        } catch (ClassNotFoundException e) {
+            throw  new RuntimeException(e);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/DefaultUriAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/DefaultUriAdapter.java
new file mode 100644
index 0000000..70f24a2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/DefaultUriAdapter.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+
+import java.util.List;
+
+
+/**
+ * Default Uri adapter. Provide basic capability to handle relative path, local file path etc.
+ * Created by sospartan on 21/11/2016.
+ */
+public class DefaultUriAdapter implements URIAdapter {
+
+
+  @NonNull
+  @Override
+  public Uri rewrite(WXSDKInstance instance, String type, Uri uri) {
+    return rewrite(instance.getBundleUrl(), type, uri);
+  }
+
+  @NonNull
+  @Override
+  public Uri rewrite(String bundleURL, String type, Uri uri) {
+    if (TextUtils.isEmpty(bundleURL)) {
+      return uri;
+    }
+
+    Uri base = Uri.parse(bundleURL);
+    Uri.Builder resultBuilder = uri.buildUpon();
+
+    if (uri.isRelative()) {
+      //When uri is empty, means use the base url instead. Web broswer behave this way.
+      if(uri.getEncodedPath().length() == 0){
+        if(IMAGE.equals(type)){
+          if(TextUtils.isEmpty(uri.toString())){
+            return uri;
+          }
+        }
+        return base;
+      } else {
+        resultBuilder = buildRelativeURI(resultBuilder, base, uri);
+        return resultBuilder.build();
+      }
+    }
+    return uri;
+  }
+
+  private Uri.Builder buildRelativeURI(Uri.Builder resultBuilder, Uri base, Uri uri) {
+    if (uri.getAuthority() != null) {
+      return resultBuilder.scheme(base.getScheme());
+    } else {
+      resultBuilder
+          .encodedAuthority(base.getEncodedAuthority())
+          .scheme(base.getScheme())
+          .path(null);
+
+      if (uri.getPath().startsWith("/")) {
+        //relative to root
+        resultBuilder.appendEncodedPath(uri.getEncodedPath().substring(1));
+      } else {
+        List<String> segments = base.getPathSegments();
+        //ignore last segment if not end with /
+        int ignoreLast = 1;
+        if (base.getPath().endsWith("/")) {
+          ignoreLast = 0;
+        }
+        for (int i = 0, len = segments.size() - ignoreLast; i < len; i++) {
+          resultBuilder.appendEncodedPath(segments.get(i));
+        }
+        resultBuilder.appendEncodedPath(uri.getEncodedPath());
+      }
+      return resultBuilder;
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/DefaultWXHttpAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/DefaultWXHttpAdapter.java
new file mode 100644
index 0000000..7f5fe12
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/DefaultWXHttpAdapter.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.WXRequest;
+import org.apache.weex.common.WXResponse;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+
+public class DefaultWXHttpAdapter implements IWXHttpAdapter {
+
+  private static final IEventReporterDelegate DEFAULT_DELEGATE = new NOPEventReportDelegate();
+  private ExecutorService mExecutorService;
+
+  private void execute(Runnable runnable){
+    if(mExecutorService==null){
+      mExecutorService = Executors.newFixedThreadPool(3);
+    }
+    mExecutorService.execute(runnable);
+  }
+
+  @Override
+  public void sendRequest(final WXRequest request, final OnHttpListener listener) {
+    if (listener != null) {
+      listener.onHttpStart();
+    }
+    execute(new Runnable() {
+      @Override
+      public void run() {
+        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(request.instanceId);
+        if (null != instance && !instance.isDestroy()){
+          instance.getApmForInstance().actionNetRequest();
+        }
+
+        boolean isNetRequestSucceed = true;
+
+        WXResponse response = new WXResponse();
+        IEventReporterDelegate reporter = getEventReporterDelegate();
+        try {
+          HttpURLConnection connection = openConnection(request, listener);
+          reporter.preConnect(connection, request.body);
+          Map<String,List<String>> headers = connection.getHeaderFields();
+          int responseCode = connection.getResponseCode();
+          if(listener != null){
+            listener.onHeadersReceived(responseCode,headers);
+          }
+          reporter.postConnect();
+
+          response.statusCode = String.valueOf(responseCode);
+          if (responseCode >= 200 && responseCode<=299) {
+            InputStream rawStream = connection.getInputStream();
+            rawStream = reporter.interpretResponseStream(rawStream);
+            response.originalData = readInputStreamAsBytes(rawStream, listener);
+          } else {
+            response.errorMsg = readInputStream(connection.getErrorStream(), listener);
+            isNetRequestSucceed = false;
+          }
+          if (listener != null) {
+            listener.onHttpFinish(response);
+          }
+        } catch (IOException|IllegalArgumentException e) {
+          isNetRequestSucceed = false;
+          e.printStackTrace();
+          response.statusCode = "-1";
+          response.errorCode="-1";
+          response.errorMsg=e.getMessage();
+          if(listener!=null){
+            listener.onHttpFinish(response);
+          }
+          if (e instanceof IOException) {
+            try {
+              reporter.httpExchangeFailed((IOException) e);
+            } catch (Throwable t) {
+              t.printStackTrace();
+            }
+          }
+        }
+        if (null != instance && !instance.isDestroy()){
+          instance.getApmForInstance().actionNetResult(isNetRequestSucceed,null);
+        }
+      }
+    });
+  }
+
+
+  /**
+   * Opens an {@link HttpURLConnection} with parameters.
+   *
+   * @param request
+   * @param listener
+   * @return an open connection
+   * @throws IOException
+   */
+  private HttpURLConnection openConnection(WXRequest request, OnHttpListener listener) throws IOException {
+    URL url = new URL(request.url);
+    HttpURLConnection connection = createConnection(url);
+    connection.setConnectTimeout(request.timeoutMs);
+    connection.setReadTimeout(request.timeoutMs);
+    connection.setUseCaches(false);
+    connection.setDoInput(true);
+
+    if (request.paramMap != null) {
+      Set<String> keySets = request.paramMap.keySet();
+      for (String key : keySets) {
+        connection.addRequestProperty(key, request.paramMap.get(key));
+      }
+    }
+
+    if ("POST".equals(request.method) || "PUT".equals(request.method) || "PATCH".equals(request.method)) {
+      connection.setRequestMethod(request.method);
+      if (request.body != null) {
+        if (listener != null) {
+          listener.onHttpUploadProgress(0);
+        }
+        connection.setDoOutput(true);
+        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
+        //TODO big stream will cause OOM; Progress callback is meaningless
+        out.write(request.body.getBytes());
+        out.close();
+        if (listener != null) {
+          listener.onHttpUploadProgress(100);
+        }
+      }
+    } else if (!TextUtils.isEmpty(request.method)) {
+      connection.setRequestMethod(request.method);
+    } else {
+      connection.setRequestMethod("GET");
+    }
+
+    return connection;
+  }
+
+  private byte[] readInputStreamAsBytes(InputStream inputStream,OnHttpListener listener) throws IOException{
+    if(inputStream == null){
+      return null;
+    }
+    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+    int nRead;
+    int readCount = 0;
+    byte[] data = new byte[2048];
+
+    while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+      buffer.write(data, 0, nRead);
+      readCount += nRead;
+      if (listener != null) {
+        listener.onHttpResponseProgress(readCount);
+      }
+    }
+
+    buffer.flush();
+
+    return buffer.toByteArray();
+  }
+
+  private String readInputStream(InputStream inputStream, OnHttpListener listener) throws IOException {
+    if(inputStream == null){
+      return null;
+    }
+    StringBuilder builder = new StringBuilder();
+    BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(inputStream));
+    char[] data = new char[2048];
+    int len;
+    while ((len = localBufferedReader.read(data)) != -1) {
+      builder.append(data, 0, len);
+      if (listener != null) {
+        listener.onHttpResponseProgress(builder.length());
+      }
+    }
+    localBufferedReader.close();
+    return builder.toString();
+  }
+
+  /**
+   * Create an {@link HttpURLConnection} for the specified {@code url}.
+   */
+  protected HttpURLConnection createConnection(URL url) throws IOException {
+    return (HttpURLConnection) url.openConnection();
+  }
+
+  public @NonNull IEventReporterDelegate getEventReporterDelegate() {
+    return DEFAULT_DELEGATE;
+  }
+
+  public interface IEventReporterDelegate {
+    void preConnect(HttpURLConnection connection, @Nullable String body);
+    void postConnect();
+    InputStream interpretResponseStream(@Nullable InputStream inputStream);
+    void httpExchangeFailed(IOException e);
+  }
+
+  private static class NOPEventReportDelegate implements IEventReporterDelegate {
+    @Override
+    public void preConnect(HttpURLConnection connection, @Nullable String body) {
+      //do nothing
+    }
+
+    @Override
+    public void postConnect() {
+      //do nothing
+    }
+
+    @Override
+    public InputStream interpretResponseStream(@Nullable InputStream inputStream) {
+      return inputStream;
+    }
+
+    @Override
+    public void httpExchangeFailed(IOException e) {
+      //do nothing
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/DrawableStrategy.java b/android/sdk/src/main/java/org/apache/weex/adapter/DrawableStrategy.java
new file mode 100644
index 0000000..60fca0d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/DrawableStrategy.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+
+public class DrawableStrategy {
+
+  public int width;
+  public int height;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/ICrashInfoReporter.java b/android/sdk/src/main/java/org/apache/weex/adapter/ICrashInfoReporter.java
new file mode 100644
index 0000000..254fa45
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/ICrashInfoReporter.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+/**
+ * Created by zhengshihan on 2017/5/23.
+ */
+
+public interface ICrashInfoReporter {
+  void addCrashInfo(String key ,String value);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IDrawableLoader.java b/android/sdk/src/main/java/org/apache/weex/adapter/IDrawableLoader.java
new file mode 100644
index 0000000..c71351d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IDrawableLoader.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
+
+public interface IDrawableLoader {
+
+  interface DrawableTarget {
+    void setDrawable(@Nullable Drawable drawable, boolean resetBounds);
+  }
+
+  interface StaticTarget extends DrawableTarget{
+    void setDrawable(@Nullable Drawable drawable, boolean resetBounds);
+  }
+
+  interface AnimatedTarget extends DrawableTarget{
+    void setAnimatedDrawable(@Nullable Drawable drawable);
+  }
+
+  void setDrawable(String url, DrawableTarget drawableTarget, DrawableStrategy drawableStrategy);
+}
+
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/ITracingAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/ITracingAdapter.java
new file mode 100644
index 0000000..e0ce304
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/ITracingAdapter.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import org.apache.weex.tracing.WXTracing;
+
+/**
+ * Created by moxun on 2017/7/6.
+ */
+
+public interface ITracingAdapter {
+  void enable();
+  void disable();
+  void submitTracingEvent(WXTracing.TraceEvent event);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXAccessibilityRoleAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXAccessibilityRoleAdapter.java
new file mode 100644
index 0000000..7682339
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXAccessibilityRoleAdapter.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+/**
+ * Created by moxun on 2017/11/13.
+ */
+
+public interface IWXAccessibilityRoleAdapter {
+  String getRole(String key);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXConfigAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXConfigAdapter.java
new file mode 100644
index 0000000..17791e3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXConfigAdapter.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+/**
+ * @author zhongcang
+ * @date 2019/3/20
+ */
+public interface IWXConfigAdapter {
+    String getConfig(String nameSpace,String key,String defaultValue);
+    String getConfigWhenInit(String nameSpace,String key,String defaultValue);
+    boolean checkMode(String name);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXHttpAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXHttpAdapter.java
new file mode 100644
index 0000000..0da8e24
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXHttpAdapter.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+
+import org.apache.weex.common.WXRequest;
+import org.apache.weex.common.WXResponse;
+
+import java.util.List;
+import java.util.Map;
+
+public interface IWXHttpAdapter {
+
+  /**
+   * http request method
+   *
+   * @param request weex assemble request
+   * @param listener http response notify
+   */
+  void sendRequest(WXRequest request, OnHttpListener listener);
+
+  interface OnHttpListener {
+
+    /**
+     * start request
+     */
+    void onHttpStart();
+
+    /**
+     * headers received
+     */
+    void onHeadersReceived(int statusCode,Map<String,List<String>> headers);
+
+    /**
+     * post progress
+     * @param uploadProgress
+     */
+    void onHttpUploadProgress(int uploadProgress);
+
+    /**
+     * response loaded length (bytes), full length should read from headers (content-length)
+     * @param loadedLength
+     */
+    void onHttpResponseProgress(int loadedLength);
+
+    /**
+     * http response finish
+     * @param response
+     */
+    void onHttpFinish(WXResponse response);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXImgLoaderAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXImgLoaderAdapter.java
new file mode 100644
index 0000000..ffbad52
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXImgLoaderAdapter.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import android.widget.ImageView;
+
+import org.apache.weex.common.WXImageStrategy;
+import org.apache.weex.dom.WXImageQuality;
+
+/**
+ * Interface for ImageLoader. This interface works as an adapter for various image library.
+ */
+public interface IWXImgLoaderAdapter {
+
+  void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy strategy);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXJSExceptionAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXJSExceptionAdapter.java
new file mode 100644
index 0000000..0bedb93
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXJSExceptionAdapter.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import org.apache.weex.common.WXJSExceptionInfo;
+
+public interface IWXJSExceptionAdapter {
+
+  /**
+   * report js exception
+   *
+   * @param exception {@link WXJSExceptionInfo}
+   */
+
+  void onJSException(WXJSExceptionInfo exception);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXJsFileLoaderAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXJsFileLoaderAdapter.java
new file mode 100644
index 0000000..4af0623
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXJsFileLoaderAdapter.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+public interface IWXJsFileLoaderAdapter {
+    String loadRaxApi();
+    String loadJsFramework();
+    String loadJsFrameworkForSandBox();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXJscProcessManager.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXJscProcessManager.java
new file mode 100644
index 0000000..1bce4a8
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXJscProcessManager.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import org.apache.weex.WXSDKInstance;
+
+public interface IWXJscProcessManager {
+    boolean enableBackupThread();
+    boolean enableBackUpThreadCache();
+    boolean shouldReboot();
+    long rebootTimeout();
+    boolean withException(WXSDKInstance instance);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXSoLoaderAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXSoLoaderAdapter.java
new file mode 100644
index 0000000..c652566
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXSoLoaderAdapter.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+/**
+ * Interface for loading library.
+ */
+public interface IWXSoLoaderAdapter {
+  /**
+   * A method <code>doLoadLibrary</code> that
+   * helps embedders to load a shared library with a short name.
+   * <p>
+   *
+   * Embedders would have a chance to take charge of library loading,
+   * they could load libraries with different class loaders,
+   * or load libraries from specified library pathes.
+   *
+   * @param shortName the name of the library
+   */
+  void doLoadLibrary(String shortName);
+
+  /**
+   * A method <code>doLoad</code> that
+   * helps embedders to load a shared library.
+   * <p>
+   *
+   * Embedders would have a chance to take charge of library loading,
+   * they could load libraries with different class loaders,
+   * or load libraries from specified library pathes.
+   *
+   * @param name the file to load.
+   */
+  void doLoad(String name);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/IWXUserTrackAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/IWXUserTrackAdapter.java
new file mode 100644
index 0000000..fcdd711
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/IWXUserTrackAdapter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import android.content.Context;
+
+import org.apache.weex.common.WXPerformance;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Interface for commit log info. This interface works as an adapter for various log library.
+ */
+public interface IWXUserTrackAdapter {
+
+  String MODULE_NAME = "weex";
+
+  //Performance
+  String LOAD = "load";
+
+  //Alarm
+  String JS_FRAMEWORK = "jsFramework";
+  String JS_DOWNLOAD = "jsDownload";
+  String DOM_MODULE = "domModule";
+  String JS_BRIDGE = "jsBridge";
+  String STREAM_MODULE = "streamModule";
+  String INVOKE_MODULE = "invokeModule";
+  String INIT_FRAMEWORK = "initFramework";
+  String COUNTER = "counter";
+
+  /**
+   * monitor keys
+   */
+  String MONITOR_ERROR_CODE = "errCode";
+  String MONITOR_ARG = "arg";
+  String MONITOR_ERROR_MSG = "errMsg";
+
+  void commit(Context context, String eventId, String type, WXPerformance perf, Map<String, Serializable> params);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/adapter/URIAdapter.java b/android/sdk/src/main/java/org/apache/weex/adapter/URIAdapter.java
new file mode 100644
index 0000000..264dc17
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/adapter/URIAdapter.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.adapter;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import org.apache.weex.WXSDKInstance;
+
+/**
+ * Created by sospartan on 15/11/2016.
+ */
+
+public interface URIAdapter {
+
+  /**
+   * Stream request url.
+   */
+  String REQUEST = "request";
+
+  /**
+   * URI for image src.
+   */
+  String IMAGE = "image";
+
+  /**
+   * Font file URI for text @font-face .
+   */
+  String FONT = "font";
+
+  /**
+   * Video URI.
+   */
+  String VIDEO = "video";
+
+  /**
+   * URI for a 'href' attribute.
+   */
+  String LINK = "link";
+
+  /**
+   * Bundle URI for Weex instance.
+   */
+  String BUNDLE = "bundle";
+
+  /**
+   * Web page src
+   */
+  String WEB = "web";
+
+  /**
+   * Unknown URIs.
+   */
+  String OTHERS = "others";
+
+  /**
+   *
+   * @param type URI type, see {@link #IMAGE}/{@link #LINK}/{@link #FONT}/{@link #BUNDLE}/{@link #VIDEO}/{@link #OTHERS}
+   * @param uri
+   * @return
+   */
+  @NonNull Uri rewrite(WXSDKInstance instance, String type, Uri uri);
+  @NonNull Uri rewrite(String bundleURL, String type, Uri uri);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/annotation/Component.java b/android/sdk/src/main/java/org/apache/weex/annotation/Component.java
new file mode 100644
index 0000000..7174925
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/annotation/Component.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Created by sospartan on 6/12/16.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Component {
+  boolean lazyload() default true;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/annotation/JSMethod.java b/android/sdk/src/main/java/org/apache/weex/annotation/JSMethod.java
new file mode 100644
index 0000000..7f8ce5b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/annotation/JSMethod.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Created by sospartan on 19/10/2016.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Target(ElementType.METHOD)
+public @interface JSMethod {
+  boolean uiThread() default true;
+
+  String alias() default NOT_SET;
+
+  String NOT_SET = "_";
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/clipboard/IWXClipboard.java b/android/sdk/src/main/java/org/apache/weex/appfram/clipboard/IWXClipboard.java
new file mode 100644
index 0000000..1c09643
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/clipboard/IWXClipboard.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.clipboard;
+
+import android.support.annotation.Nullable;
+
+import org.apache.weex.bridge.JSCallback;
+
+/**
+ * Created by yiyuan.zhangyy(xingjiu) <br/>
+ */
+interface IWXClipboard {
+    public void setString(String text);
+    public void getString(@Nullable JSCallback callback);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/clipboard/WXClipboardModule.java b/android/sdk/src/main/java/org/apache/weex/appfram/clipboard/WXClipboardModule.java
new file mode 100644
index 0000000..b38f9f0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/clipboard/WXClipboardModule.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.clipboard;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.net.Uri;
+import android.support.annotation.Nullable;
+
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class WXClipboardModule extends WXModule implements IWXClipboard {
+
+    private final String CLIP_KEY = "WEEX_CLIP_KEY_MAIN";
+
+    private static final String RESULT = "result";
+    private static final String DATA = "data";
+
+    private static final String RESULT_OK = "success";
+    private static final String RESULT_FAILED = "failed";
+
+    @Override
+    @JSMethod
+    public void setString(String text) {
+        if(null == text) {
+            return;
+        }
+
+        Context context = mWXSDKInstance.getContext();
+        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(context.CLIPBOARD_SERVICE);
+        ClipData clip = ClipData.newPlainText(CLIP_KEY, text);
+        clipboard.setPrimaryClip(clip);
+    }
+
+    @Override
+    @JSMethod
+    public void getString(@Nullable JSCallback callback) {
+        Context context = mWXSDKInstance.getContext();
+        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+
+        Map<String, Object> map = new HashMap<>(2);
+        ClipData clip = clipboard.getPrimaryClip();
+        if (clip != null && clip.getItemCount() > 0) {
+            ClipData.Item item = clip.getItemAt(0);
+            CharSequence text = coerceToText(context, item);
+
+            map.put(RESULT, text != null ? RESULT_OK : RESULT_FAILED);
+            map.put(DATA, text != null ? text : "");
+        } else {
+            map.put(RESULT, RESULT_FAILED);
+            map.put(DATA, "");
+        }
+
+        if (null != callback) {
+            callback.invoke(map);
+        }
+    }
+
+    @Nullable
+    private CharSequence coerceToText(Context context, ClipData.Item item) {
+        // Condition 1. just a simple text
+        CharSequence text = item.getText();
+        if (text != null) {
+            return text;
+        }
+
+        // Condition 2. a URI value
+        Uri uri = item.getUri();
+        if (uri != null) {
+            InputStreamReader reader = null;
+            FileInputStream stream = null;
+            try {
+                AssetFileDescriptor assetFileDescriptor = context.getContentResolver().openTypedAssetFileDescriptor(uri, "text/*", null);
+                stream = assetFileDescriptor.createInputStream();
+                reader = new InputStreamReader(stream, "UTF-8");
+
+                StringBuilder builder = new StringBuilder(128);
+                char[] buffer = new char[8192];
+                int len;
+                while ((len = reader.read(buffer)) > 0) {
+                    builder.append(buffer, 0, len);
+                }
+                return builder.toString();
+
+            } catch (FileNotFoundException e) {
+                //  ignore.
+            } catch (IOException e) {
+                WXLogUtils.w("ClippedData Failure loading text.", e);
+            } finally {
+                if (reader != null) {
+                    try {
+                        reader.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+                if (stream != null) {
+                    try {
+                        stream.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
+
+            return uri.toString();
+        }
+
+        // Condition 3.  an intent.
+        Intent intent = item.getIntent();
+        if (intent != null) {
+            return intent.toUri(Intent.URI_INTENT_SCHEME);
+        }
+
+        // else case
+        return null;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/navigator/IActivityNavBarSetter.java b/android/sdk/src/main/java/org/apache/weex/appfram/navigator/IActivityNavBarSetter.java
new file mode 100644
index 0000000..6f97e84
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/navigator/IActivityNavBarSetter.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.navigator;
+
+/**
+ *  Define the  NavBarSetter api of the Activity
+ */
+public interface IActivityNavBarSetter {
+
+  boolean push(String param);
+
+  boolean pop(String param);
+
+  boolean setNavBarRightItem(String param);
+
+  boolean clearNavBarRightItem(String param);
+
+  boolean setNavBarLeftItem(String param);
+
+  boolean clearNavBarLeftItem(String param);
+
+  boolean setNavBarMoreItem(String param);
+
+  boolean clearNavBarMoreItem(String param);
+
+  boolean setNavBarTitle(String param);
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/navigator/INavigator.java b/android/sdk/src/main/java/org/apache/weex/appfram/navigator/INavigator.java
new file mode 100644
index 0000000..60ddbb4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/navigator/INavigator.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.navigator;
+import android.app.Activity;
+
+/**
+ * Created by zhengshihan on 2018/8/9.
+ */
+
+public interface INavigator {
+
+  boolean push(Activity activity,String param);
+
+  boolean pop(Activity activity,String param);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/navigator/WXNavigatorModule.java b/android/sdk/src/main/java/org/apache/weex/appfram/navigator/WXNavigatorModule.java
new file mode 100644
index 0000000..674c89d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/navigator/WXNavigatorModule.java
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.navigator;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.utils.WXLogUtils;
+
+
+public class WXNavigatorModule extends WXModule {
+
+    public static final String MSG_SUCCESS = "WX_SUCCESS";
+    public static final String MSG_FAILED = "WX_FAILED";
+    public static final String MSG_PARAM_ERR = "WX_PARAM_ERR";
+
+    public static final String CALLBACK_RESULT = "result";
+    public static final String CALLBACK_MESSAGE = "message";
+
+    private final static String INSTANCE_ID = "instanceId";
+    private final static String TAG = "Navigator";
+    private final static String WEEX = "com.taobao.android.intent.category.WEEX";
+    private final static String URL = "url";
+
+    @JSMethod(uiThread = true)
+    public void open(JSONObject options, JSCallback success, JSCallback failure) {
+        if (options != null) {
+            String url = options.getString(Constants.Value.URL);
+            JSCallback callback = success;
+            JSONObject result = new JSONObject();
+            if (!TextUtils.isEmpty(url)) {
+                Uri rawUri = Uri.parse(url);
+                String scheme = rawUri.getScheme();
+                if (TextUtils.isEmpty(scheme) || Constants.Scheme.HTTP.equalsIgnoreCase(scheme) || Constants.Scheme.HTTPS.equalsIgnoreCase(scheme)) {
+                    this.push(options.toJSONString(), success);
+                } else {
+                    try {
+                        Intent intent = new Intent(Intent.ACTION_VIEW, rawUri);
+                        mWXSDKInstance.getContext().startActivity(intent);
+                        result.put(CALLBACK_RESULT, MSG_SUCCESS);
+                    } catch (Throwable e) {
+                        e.printStackTrace();
+                        result.put(CALLBACK_RESULT, MSG_FAILED);
+                        result.put(CALLBACK_MESSAGE, "Open page failed.");
+                        callback = failure;
+                    }
+                }
+            } else {
+                result.put(CALLBACK_RESULT, MSG_PARAM_ERR);
+                result.put(CALLBACK_MESSAGE, "The URL parameter is empty.");
+                callback = failure;
+            }
+
+            if(callback != null){
+                callback.invoke(result);
+            }
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void close(JSONObject options, JSCallback success, JSCallback failure) {
+        JSONObject result = new JSONObject();
+        JSCallback callback = null;
+        if (mWXSDKInstance.getContext() instanceof Activity) {
+            callback = success;
+            ((Activity) mWXSDKInstance.getContext()).finish();
+        } else {
+            result.put(CALLBACK_RESULT, MSG_FAILED);
+            result.put(CALLBACK_MESSAGE, "Close page failed.");
+            callback = failure;
+        }
+        if (callback != null) {
+            callback.invoke(result);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void push(String param, JSCallback callback) {
+
+        if (!TextUtils.isEmpty(param)) {
+            if (WXSDKEngine.getActivityNavBarSetter() != null) {
+                if (WXSDKEngine.getActivityNavBarSetter().push(param)) {
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                    return;
+                }
+            }
+
+            if (mWXSDKInstance.getContext() instanceof Activity){
+                Activity activity = (Activity)mWXSDKInstance.getContext();
+
+                if (WXSDKEngine.getNavigator()!= null
+                    && WXSDKEngine.getNavigator().push(activity,param)) {
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                    return;
+                }
+            }
+
+            try {
+                JSONObject jsonObject = JSON.parseObject(param);
+                String url = jsonObject.getString(URL);
+                if (!TextUtils.isEmpty(url)) {
+                    Uri rawUri = Uri.parse(url);
+                    String scheme = rawUri.getScheme();
+                    Uri.Builder builder = rawUri.buildUpon();
+                    if (TextUtils.isEmpty(scheme)) {
+                        builder.scheme(Constants.Scheme.HTTP);
+                    }
+                    Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
+                    intent.addCategory(WEEX);
+                    intent.putExtra(INSTANCE_ID, mWXSDKInstance.getInstanceId());
+                    mWXSDKInstance.getContext().startActivity(intent);
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                }
+            } catch (Exception e) {
+                WXLogUtils.eTag(TAG, e);
+                if (callback != null) {
+                    callback.invoke(MSG_FAILED);
+                }
+            }
+        } else if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void pop(String param, JSCallback callback) {
+
+        if (WXSDKEngine.getActivityNavBarSetter() != null) {
+            if (WXSDKEngine.getActivityNavBarSetter().pop(param)) {
+                if (callback != null) {
+                    callback.invoke(MSG_SUCCESS);
+                }
+                return;
+            }
+        }
+
+        if (mWXSDKInstance.getContext() instanceof Activity) {
+            Activity activity = (Activity) mWXSDKInstance.getContext();
+            if (WXSDKEngine.getNavigator() != null) {
+                if (WXSDKEngine.getNavigator().pop(activity, param)) {
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                    return;
+                }
+            }
+
+            if (callback != null) {
+                callback.invoke(MSG_SUCCESS);
+            }
+            ((Activity) mWXSDKInstance.getContext()).finish();
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void setNavBarRightItem(String param, JSCallback callback) {
+        if (!TextUtils.isEmpty(param)) {
+            if (WXSDKEngine.getActivityNavBarSetter() != null) {
+                if (WXSDKEngine.getActivityNavBarSetter().setNavBarRightItem(param)) {
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                    return;
+                }
+            }
+        }
+
+        if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void clearNavBarRightItem(String param, JSCallback callback) {
+        if (WXSDKEngine.getActivityNavBarSetter() != null) {
+            if (WXSDKEngine.getActivityNavBarSetter().clearNavBarRightItem(param)) {
+                if (callback != null) {
+                    callback.invoke(MSG_SUCCESS);
+                }
+                return;
+            }
+        }
+        if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void setNavBarLeftItem(String param, JSCallback callback) {
+        if (!TextUtils.isEmpty(param)) {
+            if (WXSDKEngine.getActivityNavBarSetter() != null) {
+                if (WXSDKEngine.getActivityNavBarSetter().setNavBarLeftItem(param)) {
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                    return;
+                }
+            }
+        }
+
+        if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+
+    }
+
+    @JSMethod(uiThread = true)
+    public void clearNavBarLeftItem(String param, JSCallback callback) {
+        if (WXSDKEngine.getActivityNavBarSetter() != null) {
+            if (WXSDKEngine.getActivityNavBarSetter().clearNavBarLeftItem(param)) {
+                if (callback != null) {
+                    callback.invoke(MSG_SUCCESS);
+                }
+                return;
+            }
+        }
+
+        if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void setNavBarMoreItem(String param, JSCallback callback) {
+        if (!TextUtils.isEmpty(param)) {
+            if (WXSDKEngine.getActivityNavBarSetter() != null) {
+                if (WXSDKEngine.getActivityNavBarSetter().setNavBarMoreItem(param)) {
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                    return;
+                }
+            }
+        }
+
+        if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void clearNavBarMoreItem(String param, JSCallback callback) {
+        if (WXSDKEngine.getActivityNavBarSetter() != null) {
+            if (WXSDKEngine.getActivityNavBarSetter().clearNavBarMoreItem(param)) {
+                if (callback != null) {
+                    callback.invoke(MSG_SUCCESS);
+                }
+                return;
+            }
+        }
+
+        if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void setNavBarTitle(String param, JSCallback callback) {
+        if (!TextUtils.isEmpty(param)) {
+            if (WXSDKEngine.getActivityNavBarSetter() != null) {
+                if (WXSDKEngine.getActivityNavBarSetter().setNavBarTitle(param)) {
+                    if (callback != null) {
+                        callback.invoke(MSG_SUCCESS);
+                    }
+                    return;
+                }
+            }
+        }
+        if (callback != null) {
+            callback.invoke(MSG_FAILED);
+        }
+    }
+
+    @JSMethod
+    public void setNavBarHidden(String param, final String callback) {
+        String message = MSG_FAILED;
+        try {
+            JSONObject jsObj = JSON.parseObject(param);
+            int visibility = jsObj.getInteger(Constants.Name.NAV_BAR_VISIBILITY);
+            boolean success = changeVisibilityOfActionBar(mWXSDKInstance.getContext(), visibility);
+            if (success) {
+                message = MSG_SUCCESS;
+            }
+        } catch (JSONException e) {
+            WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
+        }
+        WXBridgeManager.getInstance().callback(mWXSDKInstance.getInstanceId(), callback, message);
+    }
+
+    private boolean changeVisibilityOfActionBar(Context context, int visibility) {
+        boolean result = false;
+        boolean hasAppCompatActivity = false;
+        try {
+            Class.forName("android.support.v7.app.AppCompatActivity");
+            hasAppCompatActivity = true;
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+        if (hasAppCompatActivity && mWXSDKInstance.getContext() instanceof AppCompatActivity) {
+            android.support.v7.app.ActionBar actionbar = ((AppCompatActivity) mWXSDKInstance.getContext()).getSupportActionBar();
+            if (actionbar != null) {
+                switch (visibility) {
+                    case Constants.Value.NAV_BAR_HIDDEN:
+                        actionbar.hide();
+                        result = true;
+                        break;
+                    case Constants.Value.NAV_BAR_SHOWN:
+                        actionbar.show();
+                        result = true;
+                        break;
+                }
+            }
+        } else if (mWXSDKInstance.getContext() instanceof Activity) {
+            android.app.ActionBar actionbar = ((Activity) mWXSDKInstance.getContext()).getActionBar();
+            if (actionbar != null) {
+                switch (visibility) {
+                    case Constants.Value.NAV_BAR_HIDDEN:
+                        actionbar.hide();
+                        result = true;
+                        break;
+                    case Constants.Value.NAV_BAR_SHOWN:
+                        actionbar.show();
+                        result = true;
+                        break;
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/pickers/DatePickerImpl.java b/android/sdk/src/main/java/org/apache/weex/appfram/pickers/DatePickerImpl.java
new file mode 100644
index 0000000..9739bd6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/pickers/DatePickerImpl.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.pickers;
+
+import android.app.AlertDialog;
+import android.app.DatePickerDialog;
+import android.app.TimePickerDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.widget.Button;
+import android.widget.DatePicker;
+import android.widget.TimePicker;
+
+import org.apache.weex.common.WXThread;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Created by moxun on 16/11/23.
+ */
+
+public class DatePickerImpl {
+
+    private static final int DEFAULT_START_YEAR = 1900;
+    private static final int DEFAULT_END_YEAR = 2100;
+
+    private static SimpleDateFormat timeFormatter;
+    private static SimpleDateFormat dateFormatter;
+
+    public static void pickDate(@NonNull Context context, String value, String max, String min, @NonNull final OnPickListener listener, @Nullable Map<String, Object> extras) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(parseDate(value));
+        final DatePickerDialog dialog = new DatePickerDialog(
+                context,
+                new DatePickerDialog.OnDateSetListener() {
+                    @Override
+                    public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
+                        int realMonth = monthOfYear + 1;
+                        String realMonthString = realMonth < 10 ? "0" + realMonth : String.valueOf(realMonth);
+                        String realDayString = dayOfMonth < 10 ? "0" + dayOfMonth : String.valueOf(dayOfMonth);
+                        String result = year + "-" + realMonthString + "-" + realDayString;
+                        listener.onPick(true, result);
+                    }
+                },
+                calendar.get(Calendar.YEAR),
+                calendar.get(Calendar.MONTH),
+                calendar.get(Calendar.DAY_OF_MONTH)
+        );
+
+        final DatePicker datePicker = dialog.getDatePicker();
+
+        final Calendar defaultMinDate = Calendar.getInstance(Locale.getDefault());
+        final Calendar defaultMaxDate = Calendar.getInstance(Locale.getDefault());
+
+        defaultMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
+        defaultMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
+
+        if (!TextUtils.isEmpty(min)) {
+            long minDate = parseDate(min).getTime();
+            if (datePicker.getMaxDate() >= minDate) {
+                datePicker.setMinDate(parseDate(min).getTime());
+            } else {
+                datePicker.setMinDate(defaultMinDate.getTimeInMillis());
+                datePicker.setMaxDate(defaultMaxDate.getTimeInMillis());
+            }
+        }
+        if (!TextUtils.isEmpty(max)) {
+            long maxDate = parseDate(max).getTime();
+            if (datePicker.getMinDate() <= maxDate) {
+                datePicker.setMaxDate(parseDate(max).getTime());
+            } else {
+                datePicker.setMinDate(defaultMinDate.getTimeInMillis());
+                datePicker.setMaxDate(defaultMaxDate.getTimeInMillis());
+            }
+        }
+
+        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+            @Override
+            public void onCancel(DialogInterface dialog) {
+                listener.onPick(false, null);
+            }
+        });
+
+        setButtonText(dialog, DialogInterface.BUTTON_NEGATIVE, String.valueOf(extras != null ? extras.get("cancelTitle") : null));
+        setButtonText(dialog, DialogInterface.BUTTON_POSITIVE, String.valueOf(extras != null ? extras.get("confirmTitle") : null));
+
+        dialog.show();
+    }
+
+    public static void pickTime(@NonNull Context context, String value, @NonNull final OnPickListener listener, @Nullable Map<String, Object> extras) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(parseTime(value));
+        TimePickerDialog dialog = new TimePickerDialog(
+                context,
+                new TimePickerDialog.OnTimeSetListener() {
+                    @Override
+                    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
+                        String h = hourOfDay < 10 ? "0" + hourOfDay : String.valueOf(hourOfDay);
+                        String m = minute < 10 ? "0" + minute : String.valueOf(minute);
+                        String result = h + ":" + m;
+                        listener.onPick(true, result);
+                    }
+                },
+                calendar.get(Calendar.HOUR_OF_DAY),
+                calendar.get(Calendar.MINUTE),
+                false
+        );
+
+        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+            @Override
+            public void onCancel(DialogInterface dialog) {
+                listener.onPick(false, null);
+            }
+        });
+
+        setButtonText(dialog, DialogInterface.BUTTON_NEGATIVE, String.valueOf(extras != null ? extras.get("cancelTitle") : null));
+        setButtonText(dialog, DialogInterface.BUTTON_POSITIVE, String.valueOf(extras != null ? extras.get("confirmTitle") : null));
+
+        dialog.show();
+    }
+
+    public interface OnPickListener {
+        void onPick(boolean set, @Nullable String result);
+    }
+
+    private static Date parseDate(String s) {
+        if (dateFormatter == null) {
+            dateFormatter = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
+        }
+
+        try {
+            return dateFormatter.parse(s);
+        } catch (ParseException e) {
+            //don't worry
+            WXLogUtils.w("[DatePickerImpl] " + e.toString());
+        }
+        return new Date();
+    }
+
+    private static Date parseTime(String s) {
+        if (timeFormatter == null) {
+            timeFormatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
+        }
+
+        try {
+            return timeFormatter.parse(s);
+        } catch (ParseException e) {
+            //don't worry
+            WXLogUtils.w("[DatePickerImpl] " + e.toString());
+        }
+        return new Date();
+    }
+
+    private static void setButtonText(final AlertDialog dialog, final int which, final CharSequence text) {
+        if (TextUtils.isEmpty(text) || "null".equals(text)) {
+            return;
+        }
+        try {
+            dialog.getWindow().getDecorView().post(WXThread.secure(new Runnable() {
+                @Override
+                public void run() {
+                    Button button = dialog.getButton(which);
+                    if (button != null) {
+                        button.setAllCaps(false);
+                        button.setText(text);
+                    }
+                }
+            }));
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/pickers/WXPickersModule.java b/android/sdk/src/main/java/org/apache/weex/appfram/pickers/WXPickersModule.java
new file mode 100644
index 0000000..5b312af
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/pickers/WXPickersModule.java
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.pickers;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AlertDialog;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Checkable;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by moxun on 16/10/27.
+ */
+
+public class WXPickersModule extends WXModule {
+
+    private static final String SUCCESS = "success";
+    private static final String CANCEL = "cancel";
+    private static final String ERROR = "error";
+
+    private static final String RESULT = "result";
+    private static final String DATA = "data";
+
+    private static final String KEY_VALUE = "value";
+    private static final String KEY_INDEX = "index";
+    private static final String KEY_TITLE = "title";
+    private static final String KEY_MAX = "max";
+    private static final String KEY_MIN = "min";
+    private static final String KEY_ITEMS = "items";
+
+    private static final String KEY_TITLE_COLOR = "titleColor";
+    private static final String KEY_CANCEL_TITLE_COLOR = "cancelTitleColor";
+    private static final String KEY_CONFIRM_TITLE = "confirmTitle";
+    private static final String KEY_CANCEL_TITLE = "cancelTitle";
+    private static final String KEY_CONFIRM_TITLE_COLOR = "confirmTitleColor";
+    private static final String KEY_TITLE_BACKGROUND_COLOR = "titleBackgroundColor";
+    private static final String KEY_TEXT_COLOR = "textColor";
+    private static final String KEY_SELECTION_COLOR = "selectionColor";
+
+    private int selected;
+
+    @JSMethod
+    public void pick(Map<String, Object> options, JSCallback callback) {
+        List<String> items = safeConvert(getOption(options, KEY_ITEMS, new ArrayList<String>()));
+        try {
+            performSinglePick(items, options, callback);
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+    }
+
+    @JSMethod
+    public void pickDate(Map<String, Object> options, JSCallback callback) {
+        performPickDate(options, callback);
+    }
+
+    @JSMethod
+    public void pickTime(Map<String, Object> options, JSCallback callback) {
+        performPickTime(options, callback);
+    }
+
+    private List<String> safeConvert(List src) {
+        List<String> result = new ArrayList<>(src.size());
+        for (Object obj : src) {
+            result.add(String.valueOf(obj));
+        }
+        return result;
+    }
+
+    private <T> T getOption(Map<String, Object> options, String key, T defValue) {
+        Object value = options.get(key);
+        if (value == null) {
+            return defValue;
+        } else {
+            try {
+                return (T) value;
+            } catch (Exception e) {
+                e.printStackTrace();
+                return defValue;
+            }
+        }
+    }
+
+    private int getColor(Map<String, Object> options, String key, int defValue) {
+        Object value = getOption(options, key, null);
+        if (value == null) {
+            return defValue;
+        }
+        return WXResourceUtils.getColor(value.toString(), defValue);
+    }
+
+    private void performPickTime(Map<String, Object> options, final JSCallback callback) {
+        String value = getOption(options, KEY_VALUE, "");
+        DatePickerImpl.pickTime(
+                mWXSDKInstance.getContext(),
+                value,
+                new DatePickerImpl.OnPickListener() {
+                    @Override
+                    public void onPick(boolean set, @Nullable String result) {
+                        if (set) {
+                            Map<String, Object> ret = new HashMap<>(2);
+                            ret.put(RESULT, SUCCESS);
+                            ret.put(DATA, result);
+                            callback.invoke(ret);
+                        } else {
+                            Map<String, Object> ret = new HashMap<>(2);
+                            ret.put(RESULT, CANCEL);
+                            ret.put(DATA, null);
+                            callback.invoke(ret);
+                        }
+                    }
+                },
+                options);
+    }
+
+    private void performPickDate(Map<String, Object> options, final JSCallback callback) {
+        String value = getOption(options, KEY_VALUE, "");
+        String max = getOption(options, KEY_MAX, "");
+        String min = getOption(options, KEY_MIN, "");
+        DatePickerImpl.pickDate(
+                mWXSDKInstance.getContext(),
+                value,
+                max,
+                min,
+                new DatePickerImpl.OnPickListener() {
+                    @Override
+                    public void onPick(boolean set, @Nullable String result) {
+                        if (set) {
+                            Map<String, Object> ret = new HashMap<>(2);
+                            ret.put(RESULT, SUCCESS);
+                            ret.put(DATA, result);
+                            callback.invoke(ret);
+                        } else {
+                            Map<String, Object> ret = new HashMap<>(2);
+                            ret.put(RESULT, CANCEL);
+                            ret.put(DATA, null);
+                            callback.invoke(ret);
+                        }
+                    }
+                },
+                options);
+
+    }
+
+    private void performSinglePick(final List<String> items, final Map<String, Object> options, final JSCallback callback) {
+        selected = getOption(options, KEY_INDEX, 0);
+        final int textColor = getColor(options, KEY_TEXT_COLOR, Color.TRANSPARENT);
+        final int selectionColor = getColor(options, KEY_SELECTION_COLOR, Color.TRANSPARENT);
+        final ArrayAdapter adapter = new ArrayAdapter<String>(
+            mWXSDKInstance.getContext(),
+            android.R.layout.simple_list_item_single_choice,
+            items) {
+            @NonNull
+            @Override
+            public View getView(int position, View convertView, @Nullable ViewGroup parent) {
+                View itemView =  super.getView(position, convertView, parent);
+
+                if (itemView != null && itemView instanceof Checkable) {
+                    boolean needSelected = position == selected;
+                    ((Checkable) itemView).setChecked(needSelected);
+
+                    if (needSelected) {
+                        itemView.setBackgroundColor(selectionColor);
+                    } else {
+                        itemView.setBackgroundColor(Color.TRANSPARENT);
+                    }
+                }
+
+                if (itemView instanceof TextView && textColor != Color.TRANSPARENT) {
+                    ((TextView) itemView).setTextColor(textColor);
+                }
+
+                return itemView;
+            }
+        };
+        final AlertDialog dialog =  new AlertDialog.Builder(mWXSDKInstance.getContext())
+                .setAdapter(adapter, null)
+                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        //which == -1
+                        Map<String, Object> ret = new HashMap<>(2);
+                        ret.put(RESULT, SUCCESS);
+                        ret.put(DATA, selected);
+                        callback.invoke(ret);
+                    }
+                })
+                .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        //which == -2
+                        Map<String, Object> ret = new HashMap<>(2);
+                        ret.put(RESULT, CANCEL);
+                        ret.put(DATA, -1);
+                        callback.invoke(ret);
+                    }
+                })
+                .setCustomTitle(makeTitleView(mWXSDKInstance.getContext(), options))
+                .create();
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            //pre create the content view on dialog.
+            //if not , the content view will not be created until dialog.show() called
+            dialog.create();
+        }
+
+        final ListView listView = dialog.getListView();
+        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                selected = position;
+                adapter.notifyDataSetChanged();
+            }
+        });
+
+        dialog.getWindow().getDecorView().post(WXThread.secure(new Runnable() {
+            @Override
+            public void run() {
+                Button confirm = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
+                Button cancel = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+                if (confirm != null) {
+                    String confirmTitle = getOption(options, KEY_CONFIRM_TITLE, null);
+                    int confirmColor = getColor(options, KEY_CONFIRM_TITLE_COLOR, Color.TRANSPARENT);
+
+                    if (confirmTitle != null) {
+                        confirm.setText(confirmTitle);
+                        confirm.setAllCaps(false);
+                    }
+
+                    if (confirmColor != Color.TRANSPARENT) {
+                        confirm.setTextColor(confirmColor);
+                        confirm.setAllCaps(false);
+                    }
+                }
+
+                if (cancel != null) {
+                    String cancelTitle = getOption(options, KEY_CANCEL_TITLE, null);
+                    int cancelColor = getColor(options, KEY_CANCEL_TITLE_COLOR, Color.TRANSPARENT);
+
+                    if (cancelTitle != null) {
+                        cancel.setText(cancelTitle);
+                    }
+
+                    if (cancelColor != Color.TRANSPARENT) {
+                        cancel.setTextColor(cancelColor);
+                    }
+                }
+            }
+        }));
+
+        dialog.show();
+    }
+
+    private TextView makeTitleView(Context context, Map<String, Object> options) {
+        String text = getOption(options, KEY_TITLE, null);
+        if (text == null) {
+            return null;
+        }
+        TextView textView = new TextView(context);
+        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
+        int padding = WXViewUtils.dip2px(12);
+        textView.setPadding(padding, padding, padding, padding);
+        textView.getPaint().setFakeBoldText(true);
+        textView.setBackgroundColor(getColor(options, KEY_TITLE_BACKGROUND_COLOR, Color.TRANSPARENT));
+        textView.setTextColor(getColor(options, KEY_TITLE_COLOR, Color.BLACK));
+        textView.setText(text);
+        return textView;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/storage/DefaultWXStorage.java b/android/sdk/src/main/java/org/apache/weex/appfram/storage/DefaultWXStorage.java
new file mode 100644
index 0000000..2a0a6bb
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/storage/DefaultWXStorage.java
@@ -0,0 +1,335 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.storage;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteFullException;
+import android.database.sqlite.SQLiteStatement;
+import android.support.annotation.Nullable;
+
+import org.apache.weex.common.WXThread;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class DefaultWXStorage implements IWXStorageAdapter {
+
+    private WXSQLiteOpenHelper mDatabaseSupplier;
+
+    private ExecutorService mExecutorService;
+
+    private void execute(@Nullable final Runnable runnable) {
+        if (mExecutorService == null) {
+            mExecutorService = Executors.newSingleThreadExecutor();
+        }
+
+        if(runnable != null && !mExecutorService.isShutdown() && !mExecutorService.isTerminated()) {
+            mExecutorService.execute(WXThread.secure(runnable));
+        }
+    }
+
+    public DefaultWXStorage(Context context) {
+        this.mDatabaseSupplier = new WXSQLiteOpenHelper(context);
+    }
+
+
+    @Override
+    public void setItem(final String key, final String value, final OnResultReceivedListener listener) {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                Map<String, Object> data = StorageResultHandler.setItemResult(performSetItem(key, value, false, true));
+                if (listener == null) {
+                    return;
+                }
+                listener.onReceived(data);
+            }
+        });
+    }
+
+    @Override
+    public void getItem(final String key, final OnResultReceivedListener listener) {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                Map<String, Object> data = StorageResultHandler.getItemResult(performGetItem(key));
+                if (listener == null) {
+                    return;
+                }
+                listener.onReceived(data);
+            }
+        });
+    }
+
+    @Override
+    public void removeItem(final String key, final OnResultReceivedListener listener) {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                Map<String, Object> data = StorageResultHandler.removeItemResult(performRemoveItem(key));
+                if (listener == null) {
+                    return;
+                }
+                listener.onReceived(data);
+            }
+        });
+    }
+
+    @Override
+    public void length(final OnResultReceivedListener listener) {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                Map<String, Object> data = StorageResultHandler.getLengthResult(performGetLength());
+                if (listener == null) {
+                    return;
+                }
+                listener.onReceived(data);
+            }
+        });
+    }
+
+    @Override
+    public void getAllKeys(final OnResultReceivedListener listener) {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                Map<String, Object> data = StorageResultHandler.getAllkeysResult(performGetAllKeys());
+                if (listener == null) {
+                    return;
+                }
+                listener.onReceived(data);
+            }
+        });
+    }
+
+    @Override
+    public void setItemPersistent(final String key, final String value, final OnResultReceivedListener listener) {
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                Map<String, Object> data = StorageResultHandler.setItemResult(performSetItem(key, value, true, true));
+                if (listener == null) {
+                    return;
+                }
+                listener.onReceived(data);
+            }
+        });
+    }
+
+    @Override
+    public void close() {
+        final ExecutorService needCloseService = mExecutorService;
+        execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mDatabaseSupplier.closeDatabase();
+                    if (needCloseService != null) {
+                        needCloseService.shutdown();
+                    }
+                } catch (Exception e) {
+                    WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, e.getMessage());
+                }
+            }
+        });
+        mExecutorService = null;
+    }
+
+    private boolean performSetItem(String key, String value, boolean isPersistent, boolean allowRetryWhenFull) {
+        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
+        if (database == null) {
+            return false;
+        }
+
+        WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE, "set k-v to storage(key:" + key + ",value:" + value + ",isPersistent:" + isPersistent + ",allowRetry:" + allowRetryWhenFull + ")");
+        String sql = "INSERT OR REPLACE INTO " + WXSQLiteOpenHelper.TABLE_STORAGE + " VALUES (?,?,?,?);";
+        SQLiteStatement statement = null;
+        String timeStamp = WXSQLiteOpenHelper.sDateFormatter.format(new Date());
+        try {
+            statement = database.compileStatement(sql);
+            statement.clearBindings();
+            statement.bindString(1, key);
+            statement.bindString(2, value);
+            statement.bindString(3, timeStamp);
+            statement.bindLong(4, isPersistent ? 1 : 0);
+            statement.execute();
+            return true;
+        } catch (Exception e) {
+            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute setItem :" + e.getMessage());
+            if (e instanceof SQLiteFullException) {
+                if (allowRetryWhenFull && trimToSize()) {
+                    //try again
+                    //setItem/setItemPersistent method only allow try once when occurred a sqliteFullException.
+                    WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE, "retry set k-v to storage(key:" + key + ",value:" + value + ")");
+                    return performSetItem(key, value, isPersistent, false);
+                }
+            }
+
+            return false;
+        } finally {
+            if(statement != null) {
+                statement.close();
+            }
+        }
+    }
+
+    /**
+     * remove 10% of total record(at most) ordered by timestamp.
+     * */
+    private boolean trimToSize() {
+        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
+        if (database == null) {
+            return false;
+        }
+
+        List<String> toEvict = new ArrayList<>();
+        int num = 0;
+
+        Cursor c = database.query(WXSQLiteOpenHelper.TABLE_STORAGE, new String[]{WXSQLiteOpenHelper.COLUMN_KEY, WXSQLiteOpenHelper.COLUMN_PERSISTENT}, null, null, null, null, WXSQLiteOpenHelper.COLUMN_TIMESTAMP + " ASC");
+        try {
+            int evictSize = c.getCount() / 10;
+            while (c.moveToNext()) {
+                String key = c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_KEY));
+                boolean persistent = c.getInt(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_PERSISTENT)) == 1;
+                if (!persistent && key != null) {
+                    num++;
+                    toEvict.add(key);
+                    if (num == evictSize) {
+                        break;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute trimToSize:" + e.getMessage());
+        } finally {
+            c.close();
+        }
+
+        if (num <= 0) {
+            return false;
+        }
+
+        for (String key : toEvict) {
+            performRemoveItem(key);
+        }
+        WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "remove " + num + " items by lru");
+        return true;
+    }
+
+    private String performGetItem(String key) {
+        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
+        if (database == null) {
+            return null;
+        }
+
+        Cursor c = database.query(WXSQLiteOpenHelper.TABLE_STORAGE,
+                new String[]{WXSQLiteOpenHelper.COLUMN_VALUE},
+                WXSQLiteOpenHelper.COLUMN_KEY + "=?",
+                new String[]{key},
+                null, null, null);
+        try {
+            if (c.moveToNext()) {
+                ContentValues values = new ContentValues();
+                //update timestamp
+                values.put(WXSQLiteOpenHelper.COLUMN_TIMESTAMP, WXSQLiteOpenHelper.sDateFormatter.format(new Date()));
+                int updateResult = mDatabaseSupplier.getDatabase().update(WXSQLiteOpenHelper.TABLE_STORAGE, values, WXSQLiteOpenHelper.COLUMN_KEY + "= ?", new String[]{key});
+
+                WXLogUtils.d(WXSQLiteOpenHelper.TAG_STORAGE, "update timestamp " + (updateResult == 1 ? "success" : "failed") + " for operation [getItem(key = " + key + ")]");
+                return c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_VALUE));
+            } else {
+                return null;
+            }
+        } catch (Exception e) {
+            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute getItem:" + e.getMessage());
+            return null;
+        } finally {
+            c.close();
+        }
+    }
+
+    private boolean performRemoveItem(String key) {
+        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
+        if (database == null) {
+            return false;
+        }
+
+        int count = 0;
+        try {
+            count = database.delete(WXSQLiteOpenHelper.TABLE_STORAGE,
+                    WXSQLiteOpenHelper.COLUMN_KEY + "=?",
+                    new String[]{key});
+        } catch (Exception e) {
+            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute removeItem:" + e.getMessage());
+            return false;
+        }
+        return count == 1;
+    }
+
+    private long performGetLength() {
+        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
+        if (database == null) {
+            return 0;
+        }
+
+        String sql = "SELECT count(" + WXSQLiteOpenHelper.COLUMN_KEY + ") FROM " + WXSQLiteOpenHelper.TABLE_STORAGE;
+        SQLiteStatement statement = null;
+        try {
+            statement = database.compileStatement(sql);
+            return statement.simpleQueryForLong();
+        } catch (Exception e) {
+            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute getLength:" + e.getMessage());
+            return 0;
+        } finally {
+            if(statement != null) {
+                statement.close();
+            }
+        }
+    }
+
+    private List<String> performGetAllKeys() {
+        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
+        if (database == null) {
+            return null;
+        }
+
+        List<String> result = new ArrayList<>();
+        Cursor c = database.query(WXSQLiteOpenHelper.TABLE_STORAGE, new String[]{WXSQLiteOpenHelper.COLUMN_KEY}, null, null, null, null, null);
+        try {
+            while (c.moveToNext()) {
+                result.add(c.getString(c.getColumnIndex(WXSQLiteOpenHelper.COLUMN_KEY)));
+            }
+            return result;
+        } catch (Exception e) {
+            WXLogUtils.e(WXSQLiteOpenHelper.TAG_STORAGE, "DefaultWXStorage occurred an exception when execute getAllKeys:" + e.getMessage());
+            return result;
+        } finally {
+            c.close();
+        }
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/storage/IWXStorage.java b/android/sdk/src/main/java/org/apache/weex/appfram/storage/IWXStorage.java
new file mode 100644
index 0000000..ea6dc06
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/storage/IWXStorage.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.storage;
+
+import android.support.annotation.Nullable;
+
+import org.apache.weex.bridge.JSCallback;
+
+interface IWXStorage {
+    public void setItem(String key, String value,@Nullable JSCallback callback);
+    public void getItem(String key,@Nullable JSCallback callback);
+    public void removeItem(String key,@Nullable JSCallback callback);
+    public void length(@Nullable JSCallback callback);
+    public void getAllKeys(@Nullable JSCallback callback);
+    public void setItemPersistent(String key, String value, @Nullable JSCallback callback);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/storage/IWXStorageAdapter.java b/android/sdk/src/main/java/org/apache/weex/appfram/storage/IWXStorageAdapter.java
new file mode 100644
index 0000000..543e4c3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/storage/IWXStorageAdapter.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.storage;
+
+import java.util.Map;
+import org.apache.weex.InitConfig;
+
+/**
+ * interface for {@link WXStorageModule} class.
+ * this interface works as an adapter for different storage strategy.
+ * the default is use {@link android.database.sqlite.SQLiteDatabase} to store k-v pairs.
+ * You can call {@link InitConfig.Builder#setStorageAdapter(IWXStorageAdapter)} to inject your own
+ * storage implementation.
+ * */
+public interface IWXStorageAdapter {
+    void setItem(String key, String value,OnResultReceivedListener listener);
+
+    void getItem(String key,OnResultReceivedListener listener);
+
+    void removeItem(String key,OnResultReceivedListener listener);
+
+    void length(OnResultReceivedListener listener);
+
+    void getAllKeys(OnResultReceivedListener listener);
+
+    void setItemPersistent(String key, String value, OnResultReceivedListener listener);
+
+    void close();
+
+    /**
+     * the callback of storage operation.
+     * */
+    interface OnResultReceivedListener {
+        void onReceived(Map<String,Object> data);
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/storage/StorageResultHandler.java b/android/sdk/src/main/java/org/apache/weex/appfram/storage/StorageResultHandler.java
new file mode 100644
index 0000000..4225e66
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/storage/StorageResultHandler.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.storage;
+
+import android.support.annotation.Nullable;
+
+import org.apache.weex.bridge.JSCallback;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class StorageResultHandler {
+
+    private StorageResultHandler() {
+    }
+
+    private static final String RESULT = "result";
+    private static final String DATA = "data";
+
+
+    private static final String UNDEFINED = "undefined";
+    private static final String RESULT_FAILED_NO_HANDLER = "no_handler";
+    private static final String RESULT_FAILED_INVALID_PARAM = "invalid_param";
+
+
+    private static final String RESULT_OK = "success";
+    private static final String RESULT_FAILED = "failed";
+
+
+    public static Map<String, Object> getItemResult(String result) {
+        Map<String, Object> map = new HashMap<>(4);
+        map.put(RESULT, result != null ? RESULT_OK : RESULT_FAILED);
+        map.put(DATA, result != null ? result : UNDEFINED);
+        return map;
+    }
+
+    public static Map<String, Object> setItemResult(boolean result) {
+        Map<String, Object> map = new HashMap<>(4);
+        map.put(RESULT, result ? RESULT_OK : RESULT_FAILED);
+        map.put(DATA, UNDEFINED);
+        return map;
+    }
+
+
+    public static Map<String, Object> removeItemResult(boolean result) {
+        Map<String, Object> map = new HashMap<>(4);
+        map.put(RESULT, result ? RESULT_OK : RESULT_FAILED);
+        map.put(DATA, UNDEFINED);
+        return map;
+    }
+
+    public static Map<String, Object> getLengthResult(long result) {
+        Map<String, Object> map = new HashMap<>(4);
+        map.put(RESULT, RESULT_OK);
+        map.put(DATA, result);
+        return map;
+    }
+
+    public static Map<String, Object> getAllkeysResult(List<String> result) {
+        if (result == null) {
+            result = new ArrayList<>(1);
+        }
+        Map<String, Object> map = new HashMap<>(4);
+        map.put(RESULT, RESULT_OK);
+        map.put(DATA, result);
+        return map;
+    }
+
+
+    private static void handleResult(@Nullable JSCallback callback, String result, Object data) {
+        if (callback == null) {
+            return;
+        }
+        Map<String, Object> retVal = new HashMap<>(4);
+        retVal.put(RESULT, result);
+        retVal.put(DATA, data);
+        callback.invoke(retVal);
+    }
+
+    public static void handleNoHandlerError(@Nullable JSCallback callback) {
+        handleResult(callback, RESULT_FAILED, RESULT_FAILED_NO_HANDLER);
+    }
+
+    public static void handleInvalidParam(@Nullable JSCallback callback) {
+        handleResult(callback, RESULT_FAILED, RESULT_FAILED_INVALID_PARAM);
+    }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/storage/WXSQLiteOpenHelper.java b/android/sdk/src/main/java/org/apache/weex/appfram/storage/WXSQLiteOpenHelper.java
new file mode 100644
index 0000000..1ae25f2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/storage/WXSQLiteOpenHelper.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.storage;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.apache.weex.utils.WXLogUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class WXSQLiteOpenHelper extends SQLiteOpenHelper {
+
+    private static final String DATABASE_NAME = "WXStorage";
+    private static final int DATABASE_VERSION = 2;
+    static final String TAG_STORAGE = "weex_storage";
+
+    private long mMaximumDatabaseSize = 5 * 10 * 1024 * 1024L;//50mb
+    static SimpleDateFormat sDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
+    private Context mContext;
+    private SQLiteDatabase mDb;
+
+
+    static final String TABLE_STORAGE = "default_wx_storage";
+    static final String COLUMN_KEY = "key";
+    static final String COLUMN_VALUE = "value";
+    static final String COLUMN_TIMESTAMP = "timestamp";
+    static final String COLUMN_PERSISTENT = "persistent";
+
+    private static final int SLEEP_TIME_MS = 30;
+
+    private static final String STATEMENT_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_STORAGE + " ("
+            + COLUMN_KEY
+            + " TEXT PRIMARY KEY,"
+            + COLUMN_VALUE
+            + " TEXT NOT NULL,"
+            + COLUMN_TIMESTAMP
+            + " TEXT NOT NULL,"
+            + COLUMN_PERSISTENT
+            + " INTEGER DEFAULT 0"
+            + ")";
+
+
+    public WXSQLiteOpenHelper(Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        this.mContext = context;
+    }
+
+    /**
+     * retrieve sqlite database
+     *
+     * @return a {@link SQLiteDatabase} instance or null if retrieve fails.
+     * */
+    public @Nullable SQLiteDatabase getDatabase() {
+        ensureDatabase();
+        return mDb;
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL(STATEMENT_CREATE_TABLE);
+    }
+
+
+    /**
+     * version 1:
+     *
+     *   ----------------
+     *   | key | value |
+     *   ---------------
+     *
+     * version 2:
+     *
+     *  ----------------------------------------
+     *  | key | value | timestamp | persistent |
+     *  ----------------------------------------
+     **/
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        if (oldVersion != newVersion) {
+            if(newVersion == 2 && oldVersion == 1){
+                WXLogUtils.d(TAG_STORAGE,"storage is updating from version "+oldVersion+" to version "+newVersion);
+                boolean updateResult = true;
+                try {
+                    long start = System.currentTimeMillis();
+
+                    db.beginTransaction();
+                    // update table structure
+                    String SQL_ADD_COLUMN_TIMESTAMP = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_TIMESTAMP+" TEXT;";
+                    WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_TIMESTAMP);
+                    db.execSQL(SQL_ADD_COLUMN_TIMESTAMP);
+
+                    String SQL_ADD_COLUMN_PERSISTENT = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_PERSISTENT+" INTEGER;";
+                    WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_PERSISTENT);
+                    db.execSQL(SQL_ADD_COLUMN_PERSISTENT);
+
+                    // update timestamp & persistent
+                    String SQL_UPDATE_TABLE = "UPDATE "+TABLE_STORAGE+" SET "+ COLUMN_TIMESTAMP+" = '"+sDateFormatter.format(new Date())+"' , "+ COLUMN_PERSISTENT +" = 0";
+                    WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_UPDATE_TABLE);
+                    db.execSQL(SQL_UPDATE_TABLE);
+
+                    db.setTransactionSuccessful();
+                    long time = System.currentTimeMillis() - start;
+                    WXLogUtils.d(TAG_STORAGE,"storage updated success ("+time+"ms)");
+                }catch (Exception e){
+                    WXLogUtils.d(TAG_STORAGE,"storage updated failed from version "+oldVersion+" to version "+newVersion+","+e.getMessage());
+                    updateResult = false;
+                }finally {
+                    db.endTransaction();
+                }
+                //rollback
+                if(!updateResult){
+                    WXLogUtils.d(TAG_STORAGE,"storage is rollback,all data will be removed");
+                    deleteDB();
+                    onCreate(db);
+                }
+            }else{
+                deleteDB();
+                onCreate(db);
+            }
+        }
+    }
+
+
+
+    synchronized void ensureDatabase() {
+        if (mDb != null && mDb.isOpen()) {
+            return;
+        }
+
+        try {
+            // Sometimes retrieving the database fails. We do 2 retries: first without database deletion
+            // and then with deletion.
+            for (int tries = 0; tries < 2; tries++) {
+                try {
+                    if (tries > 0) {
+                        //delete db and recreate
+                        deleteDB();
+                    }
+                    mDb = getWritableDatabase();
+                    break;
+                } catch (SQLiteException e) {
+                    e.printStackTrace();
+                }
+                // Wait before retrying.
+                try {
+                    Thread.sleep(SLEEP_TIME_MS);
+                } catch (InterruptedException ie) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+            if(mDb == null){
+                return;
+            }
+
+            createTableIfNotExists(mDb);
+
+            mDb.setMaximumSize(mMaximumDatabaseSize);
+        } catch (Throwable e) {
+            mDb = null;
+            WXLogUtils.d(TAG_STORAGE,"ensureDatabase failed, throwable = " + e.getMessage());
+        }
+
+    }
+
+    public synchronized void setMaximumSize(long size) {
+        mMaximumDatabaseSize = size;
+        if (mDb != null) {
+            mDb.setMaximumSize(mMaximumDatabaseSize);
+        }
+    }
+
+    private boolean deleteDB() {
+        closeDatabase();
+        return mContext.deleteDatabase(DATABASE_NAME);
+    }
+
+    public synchronized void closeDatabase() {
+        if (mDb != null && mDb.isOpen()) {
+            mDb.close();
+            mDb = null;
+        }
+    }
+
+    private void createTableIfNotExists(@NonNull SQLiteDatabase db) {
+        Cursor cursor = null;
+        try {
+            cursor = db.rawQuery("SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name = '"+TABLE_STORAGE+"'", null);
+            if(cursor != null && cursor.getCount() > 0) {
+                return;
+            }
+            db.execSQL(STATEMENT_CREATE_TABLE);
+        }catch (Exception e){
+            e.printStackTrace();
+        }finally {
+            if(cursor != null){
+                cursor.close();
+            }
+        }
+    }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/storage/WXStorageModule.java b/android/sdk/src/main/java/org/apache/weex/appfram/storage/WXStorageModule.java
new file mode 100644
index 0000000..cb4b6de
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/storage/WXStorageModule.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.storage;
+
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.annotation.JSMethod;
+
+import java.util.Map;
+
+public class WXStorageModule extends WXSDKEngine.DestroyableModule implements IWXStorage {
+
+    IWXStorageAdapter mStorageAdapter;
+
+    private IWXStorageAdapter ability() {
+        if (mStorageAdapter != null) {
+            return mStorageAdapter;
+        }
+        mStorageAdapter = WXSDKEngine.getIWXStorageAdapter();
+        return mStorageAdapter;
+    }
+
+
+    @Override
+    @JSMethod(uiThread = false)
+    public void setItem(String key, String value, @Nullable final JSCallback callback) {
+        if (TextUtils.isEmpty(key) || value == null) {
+            StorageResultHandler.handleInvalidParam(callback);
+            return;
+        }
+
+        IWXStorageAdapter adapter = ability();
+        if (adapter == null) {
+            StorageResultHandler.handleNoHandlerError(callback);
+            return;
+        }
+        adapter.setItem(key, value, new IWXStorageAdapter.OnResultReceivedListener() {
+            @Override
+            public void onReceived(Map<String, Object> data) {
+                if(callback != null){
+                    callback.invoke(data);
+                }
+            }
+        });
+
+
+    }
+
+    @Override
+    @JSMethod(uiThread = false)
+    public void getItem(String key, @Nullable final JSCallback callback) {
+        if (TextUtils.isEmpty(key)) {
+            StorageResultHandler.handleInvalidParam(callback);
+            return;
+        }
+
+        IWXStorageAdapter adapter = ability();
+        if (adapter == null) {
+            StorageResultHandler.handleNoHandlerError(callback);
+            return;
+        }
+        adapter.getItem(key, new IWXStorageAdapter.OnResultReceivedListener() {
+            @Override
+            public void onReceived(Map<String, Object> data) {
+                if(callback != null){
+                    callback.invoke(data);
+                }
+            }
+        });
+    }
+
+    @Override
+    @JSMethod(uiThread = false)
+    public void removeItem(String key, @Nullable final JSCallback callback) {
+        if (TextUtils.isEmpty(key)) {
+            StorageResultHandler.handleInvalidParam(callback);
+            return;
+        }
+
+        IWXStorageAdapter adapter = ability();
+        if (adapter == null) {
+            StorageResultHandler.handleNoHandlerError(callback);
+            return;
+        }
+        adapter.removeItem(key, new IWXStorageAdapter.OnResultReceivedListener() {
+            @Override
+            public void onReceived(Map<String, Object> data) {
+                if(callback != null){
+                    callback.invoke(data);
+                }
+            }
+        });
+    }
+
+    @Override
+    @JSMethod(uiThread = false)
+    public void length(@Nullable final JSCallback callback) {
+        IWXStorageAdapter adapter = ability();
+        if (adapter == null) {
+            StorageResultHandler.handleNoHandlerError(callback);
+            return;
+        }
+        adapter.length(new IWXStorageAdapter.OnResultReceivedListener() {
+            @Override
+            public void onReceived(Map<String, Object> data) {
+                if(callback != null){
+                    callback.invoke(data);
+                }
+            }
+        });
+    }
+
+    @Override
+    @JSMethod(uiThread = false)
+    public void getAllKeys(@Nullable final JSCallback callback) {
+        IWXStorageAdapter adapter = ability();
+        if (adapter == null) {
+            StorageResultHandler.handleNoHandlerError(callback);
+            return;
+        }
+        adapter.getAllKeys(new IWXStorageAdapter.OnResultReceivedListener() {
+            @Override
+            public void onReceived(Map<String, Object> data) {
+                if(callback != null){
+                    callback.invoke(data);
+                }
+            }
+        });
+    }
+
+    @Override
+    @JSMethod(uiThread = false)
+    public void setItemPersistent(String key, String value, @Nullable final JSCallback callback) {
+        if (TextUtils.isEmpty(key) || value == null) {
+            StorageResultHandler.handleInvalidParam(callback);
+            return;
+        }
+
+        IWXStorageAdapter adapter = ability();
+        if (adapter == null) {
+            StorageResultHandler.handleNoHandlerError(callback);
+            return;
+        }
+        adapter.setItemPersistent(key, value, new IWXStorageAdapter.OnResultReceivedListener() {
+            @Override
+            public void onReceived(Map<String, Object> data) {
+                if(callback != null){
+                    callback.invoke(data);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void destroy() {
+        IWXStorageAdapter adapter = ability();
+        if (adapter != null) {
+            adapter.close();
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/websocket/IWebSocketAdapter.java b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/IWebSocketAdapter.java
new file mode 100644
index 0000000..1386620
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/IWebSocketAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.websocket;
+
+import android.support.annotation.Nullable;
+
+/**
+ * Created by moxun on 16/12/27.
+ */
+
+public interface IWebSocketAdapter {
+
+    String HEADER_SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
+
+    void connect(String url, @Nullable String protocol, EventListener listener);
+
+    void send(String data);
+
+    void close(int code, String reason);
+
+    void destroy();
+
+    interface EventListener {
+        void onOpen();
+
+        void onMessage(String data);
+
+        void onClose(int code, String reason, boolean wasClean);
+
+        void onError(String msg);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/websocket/IWebSocketAdapterFactory.java b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/IWebSocketAdapterFactory.java
new file mode 100644
index 0000000..9ae2e4f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/IWebSocketAdapterFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.websocket;
+
+/**
+ * Created by moxun on 16/12/28.
+ */
+
+public interface IWebSocketAdapterFactory {
+    IWebSocketAdapter createWebSocketAdapter();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/websocket/WebSocketCloseCodes.java b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/WebSocketCloseCodes.java
new file mode 100644
index 0000000..82c7fa9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/WebSocketCloseCodes.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.websocket;
+
+/**
+ * Created by moxun on 17/1/3.
+ * @link {https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
+ */
+
+public enum WebSocketCloseCodes {
+    CLOSE_NORMAL(1000),
+    CLOSE_GOING_AWAY(1001),
+    CLOSE_PROTOCOL_ERROR(1002),
+    CLOSE_UNSUPPORTED(1003),
+    CLOSE_NO_STATUS(1005),
+    CLOSE_ABNORMAL(1006),
+    UNSUPPORTED_DATA(1007),
+    POLICY_VIOLATION(1008),
+    CLOSE_TOO_LARGE(1009),
+    MISSING_EXTENSION(1010),
+    INTERNAL_ERROR(1011),
+    SERVICE_RESTART(1012),
+    TRY_AGAIN_LATER(1013),
+    TLS_HANDSHAKE(1015);
+
+    private int code;
+
+    WebSocketCloseCodes(int code) {
+        this.code = code;
+    }
+
+    public int getCode() {
+        return code;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/appfram/websocket/WebSocketModule.java b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/WebSocketModule.java
new file mode 100644
index 0000000..7b7ccf1
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/appfram/websocket/WebSocketModule.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.appfram.websocket;
+
+import android.os.Looper;
+
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by moxun on 16/12/27.
+ */
+
+public class WebSocketModule extends WXSDKEngine.DestroyableModule {
+
+    private static final String TAG = "WebSocketModule";
+    private static final String KEY_DATA = "data";
+    private static final String KEY_CODE = "code";
+    private static final String KEY_REASON = "reason";
+    private static final String KEY_WAS_CLEAN = "wasClean";
+
+    private IWebSocketAdapter webSocketAdapter;
+    private WebSocketEventListener eventListener;
+
+    public WebSocketModule() {
+        WXLogUtils.e(TAG, "create new instance");
+    }
+
+    @JSMethod(uiThread = false)
+    public void WebSocket(String url, String protocol) {
+        if (webSocketAdapter != null) {
+            WXLogUtils.w(TAG, "close");
+            webSocketAdapter.close(WebSocketCloseCodes.CLOSE_GOING_AWAY.getCode(), WebSocketCloseCodes.CLOSE_GOING_AWAY.name());
+        }
+        webSocketAdapter = mWXSDKInstance.getWXWebSocketAdapter();
+        if (!reportErrorIfNoAdapter()) {
+            eventListener = new WebSocketEventListener();
+            webSocketAdapter.connect(url, protocol, eventListener);
+        }
+    }
+
+    @JSMethod(uiThread = false)
+    public void send(String data) {
+        if (!reportErrorIfNoAdapter()) {
+            webSocketAdapter.send(data);
+        }
+    }
+
+    @JSMethod(uiThread = false)
+    public void close(String code, String reason) {
+        if (!reportErrorIfNoAdapter()) {
+            int codeNumber = WebSocketCloseCodes.CLOSE_NORMAL.getCode();
+            if (code != null) {
+                try {
+                    codeNumber = Integer.parseInt(code);
+                } catch (NumberFormatException e) {
+                    //ignore
+                }
+            }
+            webSocketAdapter.close(codeNumber, reason);
+        }
+    }
+
+    @JSMethod(uiThread = false)
+    public void onopen(JSCallback callback) {
+        if (eventListener != null) {
+            eventListener.onOpen = callback;
+        }
+    }
+
+    @JSMethod(uiThread = false)
+    public void onmessage(JSCallback callback) {
+        if (eventListener != null) {
+            eventListener.onMessage = callback;
+        }
+    }
+
+    @JSMethod(uiThread = false)
+    public void onclose(JSCallback callback) {
+        if (eventListener != null) {
+            eventListener.onClose = callback;
+        }
+    }
+
+    @JSMethod(uiThread = false)
+    public void onerror(JSCallback callback) {
+        if (eventListener != null) {
+            eventListener.onError = callback;
+        }
+    }
+
+    @Override
+    public void destroy() {
+        Runnable destroyTask = new Runnable() {
+            @Override
+            public void run() {
+                WXLogUtils.w(TAG, "close session with instance id " + mWXSDKInstance.getInstanceId());
+                if (webSocketAdapter != null) {
+                    webSocketAdapter.destroy();
+                }
+                webSocketAdapter = null;
+                eventListener = null;
+            }
+        };
+
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            WXBridgeManager.getInstance().post(destroyTask);
+        } else {
+            destroyTask.run();
+        }
+    }
+
+    private boolean reportErrorIfNoAdapter() {
+        if (webSocketAdapter == null) {
+            if (eventListener != null) {
+                eventListener.onError("No implementation found for IWebSocketAdapter");
+            }
+            WXLogUtils.e(TAG, "No implementation found for IWebSocketAdapter");
+            return true;
+        }
+        return false;
+    }
+
+    private class WebSocketEventListener implements IWebSocketAdapter.EventListener {
+        private JSCallback onOpen;
+        private JSCallback onClose;
+        private JSCallback onError;
+        private JSCallback onMessage;
+
+        @Override
+        public void onOpen() {
+            if (onOpen != null) {
+                onOpen.invoke(new HashMap<>(0));
+            }
+        }
+
+        @Override
+        public void onMessage(String data) {
+            if (onMessage != null) {
+                Map<String, String> msg = new HashMap<>(1);
+                msg.put(KEY_DATA, data);
+                onMessage.invokeAndKeepAlive(msg);
+            }
+        }
+
+        @Override
+        public void onClose(int code, String reason, boolean wasClean) {
+            if (onClose != null) {
+                Map<String, Object> msg = new HashMap<>(3);
+                msg.put(KEY_CODE, code);
+                msg.put(KEY_REASON, reason);
+                msg.put(KEY_WAS_CLEAN, wasClean);
+                onClose.invoke(msg);
+            }
+        }
+
+        @Override
+        public void onError(String msg) {
+            if (onError != null) {
+                Map<String, String> info = new HashMap<>(1);
+                info.put(KEY_DATA, msg);
+                onError.invokeAndKeepAlive(info);
+            }
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/base/CalledByNative.java b/android/sdk/src/main/java/org/apache/weex/base/CalledByNative.java
new file mode 100644
index 0000000..a9c6fd9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/base/CalledByNative.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.base;
+public @interface CalledByNative {
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/base/FloatUtil.java b/android/sdk/src/main/java/org/apache/weex/base/FloatUtil.java
new file mode 100755
index 0000000..d2ad9c3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/base/FloatUtil.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.base;
+
+public class FloatUtil {
+
+  private static final float EPSILON = .00001f;
+
+  public static boolean floatsEqual(float f1, float f2) {
+    if (Float.isNaN(f1) || Float.isNaN(f2)) {
+      return Float.isNaN(f1) && Float.isNaN(f2);
+    }
+    return Math.abs(f2 - f1) < EPSILON;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/base/SystemMessageHandler.java b/android/sdk/src/main/java/org/apache/weex/base/SystemMessageHandler.java
new file mode 100644
index 0000000..5663b49
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/base/SystemMessageHandler.java
@@ -0,0 +1,105 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.base;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+
+public class SystemMessageHandler extends Handler implements Serializable {
+
+    private static final String TAG = "SystemMessageHandler";
+
+    private static final int SCHEDULED_WORK = 1;
+
+    private long mMessagePumpDelegateNative = 0;
+
+    private Method mMessageMethodSetAsynchronous;
+
+    private native void nativeRunWork(long delegateNative);
+
+    private SystemMessageHandler(long messagePumpDelegateNative) {
+        this.mMessagePumpDelegateNative = messagePumpDelegateNative;
+        try {
+            Class<?> messageClass = Class.forName("android.os.Message");
+            mMessageMethodSetAsynchronous = messageClass.getMethod(
+                    "setAsynchronous", new Class[]{boolean.class});
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "Failed to find android.os.Message class:" + e);
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
+        }
+    }
+
+    @CalledByNative
+    public static SystemMessageHandler create(long messagePumpDelegateNative) {
+        return new SystemMessageHandler(messagePumpDelegateNative);
+    }
+
+    @CalledByNative
+    private void scheduleWork() {
+        sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
+    }
+
+    @CalledByNative
+    private void scheduleDelayedWork(long delayMillis) {
+        sendMessageDelayed(obtainAsyncMessage(SCHEDULED_WORK), delayMillis);
+    }
+
+    @CalledByNative
+    private void stop() {
+        removeMessages(SCHEDULED_WORK);
+    }
+
+    private Message obtainAsyncMessage(int what) {
+        Message msg = Message.obtain();
+        msg.what = what;
+//        if (mMessageMethodSetAsynchronous != null) {
+//            // If invocation fails, assume this is indicative of future
+//            // failures, and avoid log spam by nulling the reflected method.
+//            try {
+//                mMessageMethodSetAsynchronous.invoke(msg, true);
+//            } catch (IllegalAccessException e) {
+//                Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
+//                mMessageMethodSetAsynchronous = null;
+//            } catch (IllegalArgumentException e) {
+//                Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
+//                mMessageMethodSetAsynchronous = null;
+//            } catch (InvocationTargetException e) {
+//                Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
+//                mMessageMethodSetAsynchronous = null;
+//            } catch (RuntimeException e) {
+//                Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
+//                mMessageMethodSetAsynchronous = null;
+//            }
+//        }
+        return msg;
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        nativeRunWork(mMessagePumpDelegateNative);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/EventResult.java b/android/sdk/src/main/java/org/apache/weex/bridge/EventResult.java
new file mode 100644
index 0000000..63b315b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/EventResult.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+/**
+ * Created by furture on 2017/10/17.
+ */
+
+public class EventResult {
+
+    private Object result;
+    private boolean success = false;
+    /**
+     * onCallback javascript event callback method
+     * @param result
+     */
+    public void onCallback(Object result){
+        this.success = true;
+        this.result = result;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public Object getResult(){
+        return  result;
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/Invoker.java b/android/sdk/src/main/java/org/apache/weex/bridge/Invoker.java
new file mode 100644
index 0000000..0b5232a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/Invoker.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Type;
+
+/**
+ * Created by sospartan on 6/16/16.
+ */
+public interface Invoker {
+  Object invoke(Object receiver,Object...params) throws InvocationTargetException, IllegalAccessException;
+
+  Type[] getParameterTypes();
+
+  boolean isRunOnUIThread();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/JSCallback.java b/android/sdk/src/main/java/org/apache/weex/bridge/JSCallback.java
new file mode 100644
index 0000000..815f19f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/JSCallback.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+/**
+ * Created by sospartan on 5/24/16.
+ */
+public interface JSCallback {
+  /**
+   * invoke javascript callback method, this method will destoryed after invoke.
+   * @param data
+   */
+  void invoke(Object data);
+
+  /**
+   * invoke javascript callback method and keep callback alive for later use.
+   * @param data
+   */
+  void invokeAndKeepAlive(Object data);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/JavascriptInvokable.java b/android/sdk/src/main/java/org/apache/weex/bridge/JavascriptInvokable.java
new file mode 100644
index 0000000..a2f0c30
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/JavascriptInvokable.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+/**
+ * Created by sospartan on 11/11/2016.
+ */
+
+public interface JavascriptInvokable {
+  String[] getMethods();
+  Invoker getMethodInvoker(String name);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/MethodInvoker.java b/android/sdk/src/main/java/org/apache/weex/bridge/MethodInvoker.java
new file mode 100644
index 0000000..812421a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/MethodInvoker.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+/**
+ * Created by sospartan on 6/16/16.
+ */
+public class MethodInvoker implements Invoker {
+
+  final Method mMethod;
+  final boolean mRunOnUIThread;
+  Type[] mParam;
+
+  public MethodInvoker(Method method){
+    this(method,false);
+  }
+
+  public MethodInvoker(Method method,boolean runInUIThread){
+    mMethod = method;
+    mParam = mMethod.getGenericParameterTypes();
+    mRunOnUIThread = runInUIThread;
+  }
+
+  @Override
+  public Object invoke(Object receiver, Object... params) throws InvocationTargetException, IllegalAccessException {
+    return mMethod.invoke(receiver,params);
+  }
+
+  @Override
+  public Type[] getParameterTypes() {
+    if(mParam ==null){
+      mParam = mMethod.getGenericParameterTypes();
+    }
+    return mParam;
+  }
+
+  @Override
+  public boolean isRunOnUIThread() {
+    return mRunOnUIThread;
+  }
+
+  @Override
+  public String toString() {
+    return mMethod.getName();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/ModuleFactory.java b/android/sdk/src/main/java/org/apache/weex/bridge/ModuleFactory.java
new file mode 100644
index 0000000..0248766
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/ModuleFactory.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import org.apache.weex.common.WXModule;
+
+/**
+ * Created by sospartan on 6/17/16.
+ */
+public interface ModuleFactory<T extends WXModule> extends JavascriptInvokable {
+
+  T buildInstance() throws IllegalAccessException, InstantiationException;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/ModuleFactoryImpl.java b/android/sdk/src/main/java/org/apache/weex/bridge/ModuleFactoryImpl.java
new file mode 100644
index 0000000..3166e0b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/ModuleFactoryImpl.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+/**
+ * Created by shiwentao on 2018/3/13.
+ */
+
+public class ModuleFactoryImpl {
+  public ModuleFactory mFactory = null;
+  public boolean hasRigster = false;
+
+  public ModuleFactoryImpl(ModuleFactory factory) {
+    mFactory = factory;
+  }
+
+  public ModuleFactoryImpl(ModuleFactory factory, boolean rigister) {
+    mFactory = factory;
+    hasRigster = rigister;
+  }
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/NativeInvokeHelper.java b/android/sdk/src/main/java/org/apache/weex/bridge/NativeInvokeHelper.java
new file mode 100644
index 0000000..ebf17ad
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/NativeInvokeHelper.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import android.util.Log;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.performance.WXAnalyzerDataTransfer;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXReflectionUtils;
+
+import java.lang.reflect.Type;
+
+/**
+ * Created by sospartan on 10/11/2016.
+ */
+
+public class NativeInvokeHelper {
+  private String mInstanceId;
+
+  public NativeInvokeHelper(String instanceId){
+    mInstanceId = instanceId;
+  }
+
+  public Object invoke(final Object target,final Invoker invoker,JSONArray args) throws Exception {
+    final Object[] params = prepareArguments(
+            invoker.getParameterTypes(),
+            args);
+
+    if (WXAnalyzerDataTransfer.isInteractionLogOpen() && invoker instanceof MethodInvoker) {
+      for (int i = 0; i < params.length; i++) {
+        if (params[i] instanceof SimpleJSCallback) {
+          final String callBackId = ((SimpleJSCallback)params[i]).getCallbackId();
+          Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][callNativeModuleStart]," + mInstanceId + "," + ((MethodInvoker) invoker).mMethod.getDeclaringClass() + "," + ((MethodInvoker) invoker).mMethod.getName() + "," + callBackId);
+          ((SimpleJSCallback) params[i]).setInvokerCallback(new SimpleJSCallback.InvokerCallback() {
+            @Override
+            public void onInvokeSuccess() {
+              Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][callNativeModuleEnd]," + mInstanceId + "," + ((MethodInvoker) invoker).mMethod.getDeclaringClass() + "," + ((MethodInvoker) invoker).mMethod.getName() + "," + callBackId);
+            }
+          });
+          break;
+        }
+      }
+    }
+
+    if (invoker.isRunOnUIThread()) {
+      WXSDKManager.getInstance().postOnUiThread(new Runnable() {
+        @Override
+        public void run() {
+          if (invoker != null) {
+            try {
+              WXSDKInstance targetInstance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
+              if (null == targetInstance || targetInstance.isDestroy()){
+                return;
+              }
+              invoker.invoke(target, params);
+            } catch (Exception e) {
+              WXLogUtils.e("NativeInvokeHelper",target + " Invoker " + invoker.toString()+" exception:"+e);
+            }
+          }
+        }
+      }, 0);
+    } else {
+      return invoker.invoke(target, params);
+    }
+    return null;
+  }
+
+  protected Object[] prepareArguments(Type[] paramClazzs, JSONArray args) throws Exception {
+    Object[] params = new Object[paramClazzs.length];
+    Object value;
+    Type paramClazz;
+    for (int i = 0; i < paramClazzs.length; i++) {
+      paramClazz = paramClazzs[i];
+      if(i>=args.size()){
+        if(!paramClazz.getClass().isPrimitive()) {
+          params[i] = null;
+          continue;
+        }else {
+          throw new Exception("[prepareArguments] method argument list not match.");
+        }
+      }
+      value = args.get(i);
+
+      if (paramClazz == JSONObject.class) {
+        if(value instanceof  JSONObject || value == null) {
+          params[i] = value;
+        }else if (value instanceof String){
+          params[i] = JSON.parseObject(value.toString());
+        }
+      } else if(JSCallback.class == paramClazz){
+        if(value instanceof String){
+          params[i] = new SimpleJSCallback(mInstanceId,(String)value);
+        }else{
+          throw new Exception("Parameter type not match.");
+        }
+      } else {
+        params[i] = WXReflectionUtils.parseArgument(paramClazz,value);
+      }
+    }
+    return params;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/RequestHandler.java b/android/sdk/src/main/java/org/apache/weex/bridge/RequestHandler.java
new file mode 100644
index 0000000..fc87a67
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/RequestHandler.java
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import static org.apache.weex.http.WXHttpUtil.KEY_USER_AGENT;
+
+import android.net.Uri;
+import android.support.annotation.Keep;
+import android.text.TextUtils;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXHttpListener;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXHttpAdapter;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.base.CalledByNative;
+import org.apache.weex.bridge.WXBridgeManager.BundType;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXRequest;
+import org.apache.weex.common.WXResponse;
+import org.apache.weex.http.WXHttpUtil;
+import org.apache.weex.utils.WXExceptionUtils;
+
+import org.apache.weex.utils.WXLogUtils;
+import java.util.HashMap;
+import java.util.Locale;
+
+public class RequestHandler {
+
+  @Keep
+  native void nativeInvokeOnSuccess(long callback, String script, String bundleType);
+  native void nativeInvokeOnFailed(long callback);
+
+  @CalledByNative
+  public static RequestHandler create() {
+    return new RequestHandler();
+  }
+
+  @CalledByNative
+  public void send(String instanceId, String url, long nativeCallback) {
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(url) ||
+        nativeCallback == 0 ||
+        !WXSDKManager.getInstance().getAllInstanceMap().containsKey(
+            instanceId)) {
+      return;
+    }
+
+    WXSDKManager manager = WXSDKManager.getInstance();
+    WXSDKInstance instance =
+        WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance == null)
+      return;
+    IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter();
+
+    WXRequest wxRequest = new WXRequest();
+    wxRequest.url = manager.getURIAdapter()
+                        .rewrite(instance, URIAdapter.BUNDLE, Uri.parse(url))
+                        .toString();
+
+    if (wxRequest.paramMap == null) {
+      wxRequest.paramMap = new HashMap<>();
+    }
+    wxRequest.paramMap.put(
+        KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(
+                            instance.getContext(), WXEnvironment.getConfig()));
+    wxRequest.paramMap.put("isBundleRequest", "true");
+    WXLogUtils.i("Eagle", String.format(Locale.ENGLISH, "Weex eagle is going to download script from %s", url));
+    adapter.sendRequest(wxRequest, new OnHttpListenerInner(instance, nativeCallback, url));
+  }
+
+  @Keep
+  @CalledByNative
+  public void getBundleType(String instanceId, final String content, final long nativeCallback){
+    BundType bundleType = WXBridgeManager.getInstance().getBundleType("", content);
+    final String bundleTypeStr = bundleType == null ? "Others" : bundleType.toString();
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if ("Others".equalsIgnoreCase(bundleTypeStr) && null != instance){
+      WXExceptionUtils.commitCriticalExceptionRT(
+          instanceId,
+          WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE,
+          "RequestHandler.onSuccess",
+          "eagle ->" +WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE.getErrorMsg(),
+          null
+      );
+    }
+    WXBridgeManager.getInstance().post(new Runnable() {
+      @Override
+      public void run() {
+        if(WXBridgeManager.getInstance().isJSFrameworkInit()) {
+          nativeInvokeOnSuccess(nativeCallback, content, bundleTypeStr);
+        }
+        else {
+          nativeInvokeOnFailed(nativeCallback);
+        }
+      }
+    });
+  }
+
+  class OnHttpListenerInner extends WXHttpListener {
+    private long sNativeCallback;
+
+    OnHttpListenerInner(WXSDKInstance instance, long nativeCallback, String bundlUrl) {
+      super(instance, bundlUrl);
+      sNativeCallback = nativeCallback;
+    }
+
+    @Override
+    public void onSuccess(WXResponse response) {
+        final String script = new String(response.originalData);
+        BundType bundleType = WXBridgeManager.getInstance().getBundleType("", script);
+        final String bundleTypeStr = bundleType == null ? "Others" : bundleType.toString();
+        if ("Others".equalsIgnoreCase(bundleTypeStr) && null != getInstance()){
+          WXExceptionUtils.commitCriticalExceptionRT(
+              getInstance().getInstanceId(),
+              WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE,
+              "RequestHandler.onSuccess",
+              "eagle ->" +WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE.getErrorMsg(),
+              null
+          );
+        }
+        WXBridgeManager.getInstance().post(new Runnable() {
+          @Override
+          public void run() {
+            if(WXBridgeManager.getInstance().isJSFrameworkInit()) {
+              nativeInvokeOnSuccess(sNativeCallback, script, bundleTypeStr);
+            }
+            else{
+              nativeInvokeOnFailed(sNativeCallback);
+            }
+          }
+        });
+    }
+
+    @Override
+    public void onFail(WXResponse response) {
+      nativeInvokeOnFailed(sNativeCallback);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/ResultCallback.java b/android/sdk/src/main/java/org/apache/weex/bridge/ResultCallback.java
new file mode 100644
index 0000000..203b3d8
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/ResultCallback.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+public interface ResultCallback<T> {
+    void onReceiveResult(T result);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/ResultCallbackManager.java b/android/sdk/src/main/java/org/apache/weex/bridge/ResultCallbackManager.java
new file mode 100644
index 0000000..d945a0f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/ResultCallbackManager.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import android.util.SparseArray;
+
+/**
+ * Manage async callbacks which waiting for the result of executing javascript
+ */
+/* default */ class ResultCallbackManager {
+    // Unique id for callback after executing js
+    private static long sCallbackId = 0;
+    // Map for save callbacks, key is id
+    private static SparseArray<ResultCallback> mResultCallbacks = new SparseArray<>();
+
+    // Generate unique id
+    static long generateCallbackId(ResultCallback callback) {
+        if (sCallbackId >= Integer.MAX_VALUE) {
+            sCallbackId = 0;
+        }
+        int id = (int) sCallbackId++;
+        mResultCallbacks.put(id, callback);
+        return id;
+    }
+
+    // Remove id from callback map
+    static ResultCallback removeCallbackById(long id) {
+        ResultCallback callback = mResultCallbacks.get((int) id);
+        mResultCallbacks.remove((int) id);
+        return callback;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/SimpleJSCallback.java b/android/sdk/src/main/java/org/apache/weex/bridge/SimpleJSCallback.java
new file mode 100644
index 0000000..ef86987
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/SimpleJSCallback.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+/**
+ * Created by sospartan on 27/10/2016.
+ */
+public class SimpleJSCallback implements JSCallback {
+
+  String mInstanceId;
+  String mCallbackId;
+
+  private InvokerCallback mInvokerCallback;
+
+  public void setInvokerCallback(InvokerCallback callback) {
+    this.mInvokerCallback = callback;
+  }
+
+  interface InvokerCallback {
+    void onInvokeSuccess();
+  }
+
+  public String getCallbackId() {
+    return mCallbackId;
+  }
+
+  public SimpleJSCallback(String instanceId, String callbackId) {
+    this.mCallbackId = callbackId;
+    this.mInstanceId = instanceId;
+  }
+
+
+  @Override
+  public void invoke(Object data) {
+    WXBridgeManager.getInstance().callbackJavascript(mInstanceId, mCallbackId, data, false);
+    if (mInvokerCallback != null) {
+      mInvokerCallback.onInvokeSuccess();
+    }
+  }
+
+  @Override
+  public void invokeAndKeepAlive(Object data) {
+    WXBridgeManager.getInstance().callbackJavascript(mInstanceId, mCallbackId, data, true);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXBridge.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridge.java
new file mode 100755
index 0000000..ac02b42
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridge.java
@@ -0,0 +1,937 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.base.CalledByNative;
+import org.apache.weex.common.IWXBridge;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.performance.WXStateRecord;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXJsonUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXWsonJSONSwitch;
+import org.apache.weex.utils.tools.TimeCalculator;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * Communication interface for Java code and JavaScript code.
+ */
+
+    public class WXBridge implements IWXBridge {
+
+  private native int nativeInitFrameworkEnv(String framework, WXParams params, String cacheDir, boolean pieSupport);
+
+  private native int nativeInitFramework(String framework, WXParams params);
+
+  private native void nativeRefreshInstance(String instanceId, String namespace, String function, WXJSObject[] args);
+
+  private native int nativeExecJS(String instanceId, String name, String function, WXJSObject[] args);
+
+  private native int nativeExecJSService(String javascript);
+
+  public native byte[] nativeExecJSWithResult(String instanceId, String _namespace, String _function, WXJSObject[] args);
+  public native void nativeExecJSWithCallback(String instanceId, String _namespace, String _function, WXJSObject[] args, long callbackId);
+
+  public native int nativeCreateInstanceContext(String instanceId, String name, String function, WXJSObject[] args);
+
+  public native int nativeDestoryInstance(String instanceId, String name, String function, WXJSObject[] args);
+
+  public native String nativeExecJSOnInstance(String instanceId, String script, int type);
+
+  public native void nativeFireEventOnDataRenderNode(String instanceId, String ref, String type, String data, String domChanges);
+
+  public native void nativeInvokeCallbackOnDataRender(String instanceId, String callbackId, String data, boolean keepAlive);
+
+  public native void nativeRegisterModuleOnDataRenderNode( String data);
+
+  public native void nativeRegisterComponentOnDataRenderNode( String data);
+
+  private native void nativeTakeHeapSnapshot(String filename);
+
+  private native void nativeBindMeasurementToRenderObject(long ptr);
+
+  private native void nativeSetRenderContainerWrapContent(boolean wrap, String instanceId);
+
+  public native long[] nativeGetFirstScreenRenderTime(String instanceId);
+
+  public native long[] nativeGetRenderFinishTime(String instanceId);
+
+  private native void nativeSetDefaultHeightAndWidthIntoRootDom(String instanceId, float defaultWidth, float defaultHeight, boolean isWidthWrapContent, boolean isHeightWrapContent);
+
+  private native void nativeOnInstanceClose(String instanceId);
+
+  private native void nativeForceLayout(String instanceId);
+
+  private native boolean nativeNotifyLayout(String instanceId);
+
+  private native void nativeSetStyleWidth(String instanceId, String ref, float value);
+
+  private native void nativeSetStyleHeight(String instanceId, String ref, float value);
+
+  private native void nativeSetMargin(String instanceId, String ref, int edge, float value);
+
+  private native void nativeSetPadding(String instanceId, String ref, int edge, float value);
+
+  private native void nativeSetPosition(String instanceId, String ref, int edge, float value);
+
+  private native void nativeMarkDirty(String instanceId, String ref, boolean dirty);
+
+  private native void nativeSetDeviceDisplay(String instanceId, float width, float height, float scale);
+
+  private native void nativeRegisterCoreEnv(String key, String value);
+
+  private native void nativeResetWXBridge(Object bridge, String className);
+
+  private native void nativeSetInstanceRenderType(String instanceId, String renderType);
+
+  private native void nativeRemoveInstanceRenderType(String instanceId);
+
+  private native void nativeSetPageArgument(String instanceId, String key, String value);
+
+  public native void nativeOnInteractionTimeUpdate(String instanceId);
+
+  public native String nativeDumpIpcPageQueueInfo();
+
+  /**
+   * Update Init Framework Params
+   * */
+  private native void nativeUpdateInitFrameworkParams(String key, String value, String desc);
+
+  /**
+   * update global config,
+   * @param config params
+   * */
+  public native void nativeUpdateGlobalConfig(String config);
+
+  private native void nativeSetViewPortWidth(String instanceId, float viewPortWidth);
+  private native void nativeSetLogType(float type, float isPerf);
+
+  private native void nativeReloadPageLayout(String instanceId);
+
+  private native void nativeSetDeviceDisplayOfPage(String instanceId,float width,float height);
+
+  public static final boolean MULTIPROCESS = true;
+
+
+  @Override
+  public void updateInitFrameworkParams(String key, String value, String desc){
+    WXStateRecord.getInstance().recordAction("","updateInitFrameworkParams:");
+     nativeUpdateInitFrameworkParams(key, value, desc);
+  }
+
+  @Override
+  public void setLogType(float type, boolean isPerf) {
+    Log.e("WeexCore", "setLog" + WXEnvironment.sLogLevel.getValue() + "isPerf : " + isPerf);
+    nativeSetLogType(type, isPerf ? 1 : 0);
+  }
+
+  @Override
+  public int initFramework(String framework, WXParams params) {
+    return nativeInitFramework(framework, params);
+  }
+
+  @Override
+  public int initFrameworkEnv(String framework, WXParams params, String cacheDir, boolean pieSupport) {
+    if (MULTIPROCESS) {
+      WXStateRecord.getInstance().recordAction("","nativeInitFrameworkEnv:");
+      return nativeInitFrameworkEnv(framework, params, cacheDir, pieSupport);
+    } else {
+      WXStateRecord.getInstance().recordAction("","nativeInitFramework:");
+      return nativeInitFramework(framework, params);
+    }
+  }
+
+  @Override
+  public void refreshInstance(String instanceId, String namespace, String function, WXJSObject[] args) {
+    WXStateRecord.getInstance().recordAction(instanceId,"refreshInstance:"+namespace+","+function);
+    nativeRefreshInstance(instanceId, namespace, function, args);
+  }
+
+  @Override
+  public int execJS(String instanceId, String namespace, String function, WXJSObject[] args) {
+    WXStateRecord.getInstance().recordAction(instanceId,"execJS:"+namespace+","+function);
+    return nativeExecJS(instanceId, namespace, function, args);
+  }
+
+  @Override
+  public void execJSWithCallback(String instanceId, String namespace, String function, WXJSObject[] args, ResultCallback callback) {
+    WXStateRecord.getInstance().recordAction(instanceId,"execJSWithCallback:"+namespace+","+function);
+    if (callback == null) {
+      execJS(instanceId, namespace, function, args);
+    }
+    nativeExecJSWithCallback(instanceId, namespace, function, args,
+            ResultCallbackManager.generateCallbackId(callback));
+  }
+
+  @CalledByNative
+  public void onNativePerformanceDataUpdate(String instanceId,Map<String,String> map){
+    if (TextUtils.isEmpty(instanceId) || null == map || map.size() < 1){
+      return;
+    }
+    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+    if (null == instance || null == instance.getApmForInstance()){
+      return;
+    }
+    instance.getApmForInstance().updateNativePerformanceData(map);
+  }
+
+  // Result from js engine
+  @CalledByNative
+  public void onReceivedResult(long callbackId, byte[] result) {
+    WXStateRecord.getInstance().recordAction("onReceivedResult","callbackId"+callbackId);
+    ResultCallback callback = ResultCallbackManager.removeCallbackById(callbackId);
+    if (callback != null) {
+       callback.onReceiveResult(result);
+    }
+  }
+
+  @Override
+  public int execJSService(String javascript) {
+    WXStateRecord.getInstance().recordAction("execJSService","execJSService:");
+    return nativeExecJSService(javascript);
+  }
+
+
+  @Override
+  public void takeHeapSnapshot(String filename) {
+    nativeTakeHeapSnapshot(filename);
+  }
+
+  @Override
+  public int createInstanceContext(String instanceId, String name, String function, WXJSObject[] args) {
+    Log.e(TimeCalculator.TIMELINE_TAG,"createInstance :" + System.currentTimeMillis());
+    WXStateRecord.getInstance().recordAction(instanceId,"createInstanceContext:");
+    return nativeCreateInstanceContext(instanceId, name, function, args);
+  }
+
+  @Override
+  public int destoryInstance(String instanceId, String name, String function, WXJSObject[] args) {
+    WXStateRecord.getInstance().recordAction(instanceId,"destoryInstance:");
+    return nativeDestoryInstance(instanceId, name, function, args);
+  }
+
+  @Override
+  public String execJSOnInstance(String instanceId, String script, int type) {
+    WXStateRecord.getInstance().recordAction(instanceId,"execJSOnInstance:"+type);
+    return nativeExecJSOnInstance(instanceId, script, type);
+  }
+
+  public static final String TAG = "WXBridge";
+
+  /**
+   * JavaScript uses this methods to call Android code
+   *
+   * @param instanceId
+   * @param tasks
+   * @param callback
+   */
+  @CalledByNative
+  public int callNative(String instanceId, byte[] tasks, String callback) {
+    if("HeartBeat".equals(callback)) {
+      Log.e("HeartBeat instanceId", instanceId);
+      WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if(sdkInstance != null) {
+        sdkInstance.createInstanceFuncHeartBeat();
+      }
+      return IWXBridge.INSTANCE_RENDERING;
+    }
+
+    return callNative(instanceId, (JSONArray) JSON.parseArray(new String(tasks)), callback);
+  }
+
+  @Override
+  public int callNative(String instanceId, String tasks, String callback) {
+    try{
+      return callNative(instanceId, JSONArray.parseArray(tasks), callback);
+    }catch (Exception e){
+      WXLogUtils.e(TAG, "callNative throw exception: " + WXLogUtils.getStackTrace(e));
+      return IWXBridge.INSTANCE_RENDERING;
+    }
+  }
+
+  private int callNative(String instanceId, JSONArray tasks, String callback){
+    long start = System.currentTimeMillis();
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance != null) {
+      instance.firstScreenCreateInstanceTime(start);
+    }
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callNative(instanceId, tasks, callback);
+    } catch (Throwable e) {
+      WXLogUtils.e(TAG, "callNative throw exception:" + WXLogUtils.getStackTrace(e));
+    }
+
+    if (WXEnvironment.isApkDebugable()) {
+      if (errorCode == IWXBridge.DESTROY_INSTANCE) {
+        WXLogUtils.w("destroyInstance :" + instanceId + " JSF must stop callNative");
+      }
+    }
+    return errorCode;
+  }
+
+  @CalledByNative
+  public void reportJSException(String instanceId, String func, String exception) {
+    WXBridgeManager.getInstance().reportJSException(instanceId, func, exception);
+  }
+
+
+  /**
+   * Bridge module Js Method
+   * support Sync or Async through setting  Annotation as {@link JSMethod }
+   *
+   * @param instanceId Instance ID
+   * @param module     the name of module
+   * @param method     the name of method
+   * @param arguments  the arguments of the method
+   * @param options    option arguments for extending
+   * @return the result
+   */
+  @Override
+  @CalledByNative
+  public Object callNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options) {
+    try {
+      WXStateRecord.getInstance().recordAction(instanceId,"callNativeModule:"+module+"."+method);
+      long start = WXUtils.getFixUnixTime();
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      JSONArray argArray = null;
+      if (arguments != null){
+        // TODO use a better way
+        if (instance!=null && (instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER
+                || instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER_BINARY)){
+          try {
+            argArray = (JSONArray) JSON.parse(new String(arguments, "UTF-8"));
+          } catch (Exception e) {
+            // For wson use in data render mode
+            argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
+          }
+        } else {
+          argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
+        }
+      }
+      JSONObject optionsObj = null;
+      if (options != null) {
+        optionsObj = (JSONObject) WXWsonJSONSwitch.parseWsonOrJSON(options);
+      } else if (argArray != null) {
+        final WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+        if (sdkInstance != null) {
+          if (WXBridgeManager.BundType.Rax.equals(sdkInstance.bundleType)) {
+            Object weex_options__ = null;
+            for (Object object: argArray) {
+              if (object instanceof JSONObject && ((JSONObject) object).containsKey("__weex_options__")) {
+                weex_options__ = ((JSONObject) object).get("__weex_options__");
+              }
+            }
+
+            if (weex_options__ instanceof JSONObject)
+              optionsObj = (JSONObject) weex_options__;
+          }
+        }
+
+      }
+
+      Object object = WXBridgeManager.getInstance().callNativeModule(instanceId, module, method, argArray, optionsObj);
+
+      if (null != instance){
+        instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_NATIVE_NUM,1);
+        instance.getApmForInstance().updateFSDiffStats(
+            WXInstanceApm.KEY_PAGE_STATS_FS_CALL_NATIVE_TIME,
+            WXUtils.getFixUnixTime()-start
+        );
+      }
+      if (instance!=null && (instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER
+          || instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER_BINARY)){
+        try {
+          if(object == null){
+            return new WXJSObject(null);
+          }
+          if(object.getClass() == WXJSObject.class){
+            return (WXJSObject) object;
+          }
+          return new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(object));
+        } catch (Exception e) {
+          // For wson use in data render mode
+          return WXWsonJSONSwitch.toWsonOrJsonWXJSObject(object);
+        }
+      } else {
+        return WXWsonJSONSwitch.toWsonOrJsonWXJSObject(object);
+      }
+    }catch (Exception e){
+      WXLogUtils.e(TAG,  e);
+      return new WXJSObject(null);
+    }
+  }
+
+  /**
+   * Bridge component Js Method
+   *
+   * @param instanceId   Instance ID
+   * @param ref the ref of component
+   * @param method       the name of method
+   * @param arguments    the arguments of the method
+   * @param options      option arguments for extending
+   */
+  @Override
+  @CalledByNative
+  public void callNativeComponent(String instanceId, String ref, String method, byte[] arguments, byte[] optionsData) {
+    WXStateRecord.getInstance().recordAction(instanceId,"callNativeComponent:"+method);
+    try{
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      JSONArray argArray = null;
+      if (arguments != null){
+        // TODO use a better way
+        if (instance!=null && (instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER
+            || instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER_BINARY)){
+          try {
+            argArray = (JSONArray) JSON.parse(new String(arguments, "UTF-8"));
+          } catch (Exception e) {
+            // For wson use in data render mode
+            argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
+          }
+        } else {
+          argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
+        }
+      }
+      Object options = WXWsonJSONSwitch.parseWsonOrJSON(optionsData);
+      WXBridgeManager.getInstance().callNativeComponent(instanceId, ref, method, argArray, options);
+    }catch (Exception e){
+      WXLogUtils.e(TAG,  e);
+    }
+  }
+
+  @Override
+  @CalledByNative
+  public void setTimeoutNative(String callbackId, String time) {
+    WXBridgeManager.getInstance().setTimeout(callbackId, time);
+  }
+
+  @Override
+  @CalledByNative
+  public void setJSFrmVersion(String version) {
+    if (version != null) {
+      WXEnvironment.JS_LIB_SDK_VERSION = version;
+    }
+    WXStateRecord.getInstance().onJSFMInit();
+  }
+
+  @Override
+  public void resetWXBridge(boolean remoteDebug) {
+    final String className = this.getClass().getName().replace('.', '/');
+    nativeResetWXBridge(this, className);
+  }
+
+  @Override
+  @CalledByNative
+  public int callUpdateFinish(String instanceId, byte[] tasks, String callback) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callUpdateFinish(instanceId, callback);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callCreateBody throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callRefreshFinish(String instanceId, byte[] tasks, String callback) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callRefreshFinish(instanceId, callback);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public void reportServerCrash(String instanceId, String crashFile) {
+    WXLogUtils.e(TAG, "reportServerCrash instanceId:" + instanceId + " crashFile: " + crashFile);
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callReportCrashReloadPage(instanceId, crashFile);
+
+      // upload crash log
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "reloadPageNative throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+  }
+
+  @Override
+  @CalledByNative
+  public int callCreateBody(String instanceId, String componentType, String ref,
+                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
+                            float[] margins, float[] paddings, float[] borders) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+
+    try {
+      errorCode = WXBridgeManager.getInstance().callCreateBody(instanceId, componentType, ref,
+              styles, attributes, events, margins, paddings, borders);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callCreateBody throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callAddElement(String instanceId, String componentType, String ref, int index, String parentRef,
+                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
+                            float[] margins, float[] paddings, float[] borders,  boolean willLayout) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+
+    try {
+      errorCode = WXBridgeManager.getInstance().callAddElement(instanceId, componentType, ref, index, parentRef,
+              styles, attributes, events, margins, paddings, borders, willLayout);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        e.printStackTrace();
+        WXLogUtils.e(TAG, "callAddElement throw error:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callRemoveElement(String instanceId, String ref) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callRemoveElement(instanceId, ref);
+    } catch (Throwable e) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callRemoveElement throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callMoveElement(String instanceId, String ref, String parentref, int index) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callMoveElement(instanceId, ref, parentref, index);
+    } catch (Throwable e) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callMoveElement throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callAddEvent(String instanceId, String ref, String event) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callAddEvent(instanceId, ref, event);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      // if(WXEnvironment.isApkDebugable()){
+      WXLogUtils.e(TAG, "callAddEvent throw exception:" + WXLogUtils.getStackTrace(e));
+      // }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callRemoveEvent(String instanceId, String ref, String event) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callRemoveEvent(instanceId, ref, event);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callRemoveEvent throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callUpdateStyle(String instanceId, String ref,
+                             HashMap<String, Object> styles,
+                             HashMap<String, String> paddings,
+                             HashMap<String, String> margins,
+                             HashMap<String, String> borders) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callUpdateStyle(instanceId, ref, styles, paddings, margins, borders);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callUpdateStyle throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callUpdateAttrs(String instanceId, String ref, HashMap<String, String> attrs) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callUpdateAttrs(instanceId, ref, attrs);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callUpdateAttr throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callAddChildToRichtext(String instanceId, String nodeType, String ref, String parentRef, String richTextRef,
+                             HashMap<String, String> styles, HashMap<String, String> attrs){
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callAddChildToRichtext(instanceId, nodeType, ref, parentRef, richTextRef,
+              styles, attrs);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callAddChildToRichtext throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+  @Override
+  @CalledByNative
+  public int callRemoveChildFromRichtext(String instanceId, String ref, String parentRef, String richTextRef){
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callRemoveChildFromRichtext(instanceId, ref, parentRef, richTextRef);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callRemoveChildFromRichtext throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callUpdateRichtextStyle(String instanceId, String ref, HashMap<String, String> styles, String parentRef, String richTextRef){
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callUpdateRichtextStyle(instanceId, ref, styles, parentRef, richTextRef);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callUpdateRichtextStyle throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+  @Override
+  @CalledByNative
+  public int callUpdateRichtextChildAttr(String instanceId, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef){
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callUpdateRichtextChildAttr(instanceId, ref, attrs, parentRef, richTextRef);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callUpdateRichtextChildAttr throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+
+  @Override
+  @CalledByNative
+  public int callLayout(String instanceId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callLayout(instanceId, ref, top, bottom, left, right, height, width, isRTL, index);
+    } catch (Throwable e) {
+      //catch everything during call native.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callLayout throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callCreateFinish(String instanceId) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callCreateFinish(instanceId);
+    } catch (Throwable e) {
+      WXLogUtils.e(TAG, "callCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callRenderSuccess(String instanceId) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callRenderSuccess(instanceId);
+    } catch (Throwable e) {
+      WXLogUtils.e(TAG, "callCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callAppendTreeCreateFinish(String instanceId, String ref) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callAppendTreeCreateFinish(instanceId, ref);
+    } catch (Throwable e) {
+      WXLogUtils.e(TAG, "callAppendTreeCreateFinish throw exception:" + WXLogUtils.getStackTrace(e));
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public int callHasTransitionPros(String instanceId, String ref, HashMap<String, String> styles) {
+    int errorCode = IWXBridge.INSTANCE_RENDERING;
+    try {
+      errorCode = WXBridgeManager.getInstance().callHasTransitionPros(instanceId, ref, styles);
+    } catch (Throwable e) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "callHasTransitionPros throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return errorCode;
+  }
+
+  @Override
+  @CalledByNative
+  public ContentBoxMeasurement getMeasurementFunc(String instanceId, long renderObjectPtr) {
+    ContentBoxMeasurement obj = null;
+    try {
+      obj = WXBridgeManager.getInstance().getMeasurementFunc(instanceId, renderObjectPtr);
+    } catch (Throwable e) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(TAG, "getMeasurementFunc throw exception:" + WXLogUtils.getStackTrace(e));
+      }
+    }
+    return obj;
+  }
+
+  @Override
+  public void bindMeasurementToRenderObject(long ptr){
+    nativeBindMeasurementToRenderObject(ptr);
+  }
+
+  @Override
+  public void setRenderContainerWrapContent(boolean wrap, String instanceId) {
+    nativeSetRenderContainerWrapContent(wrap, instanceId);
+  }
+
+  @Override
+  public long[] getFirstScreenRenderTime(String instanceId) {
+    return nativeGetFirstScreenRenderTime(instanceId);
+  }
+
+  @Override
+  public long[] getRenderFinishTime(String instanceId) {
+    return nativeGetRenderFinishTime(instanceId);
+  }
+
+  @Override
+  public void setDefaultHeightAndWidthIntoRootDom(String instanceId, float defaultWidth, float defaultHeight, boolean isWidthWrapContent, boolean isHeightWrapContent) {
+    nativeSetDefaultHeightAndWidthIntoRootDom(instanceId, defaultWidth, defaultHeight, isWidthWrapContent, isHeightWrapContent);
+  }
+
+  @Override
+  public void onInstanceClose(String instanceId) {
+    nativeOnInstanceClose(instanceId);
+  }
+
+  @Override
+  public void forceLayout(String instanceId) {
+    nativeForceLayout(instanceId);
+  }
+
+  @Override
+  public boolean notifyLayout(String instanceId) {
+    return nativeNotifyLayout(instanceId);
+  }
+
+  @Override
+  public void setStyleWidth(String instanceId, String ref, float value) {
+    nativeSetStyleWidth(instanceId, ref, value);
+  }
+
+  @Override
+  public void setMargin(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
+    nativeSetMargin(instanceId, ref, edge.ordinal(), value);
+  }
+
+  @Override
+  public void setPadding(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
+    nativeSetPadding(instanceId, ref, edge.ordinal(), value);
+  }
+
+  @Override
+  public void setPosition(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
+    nativeSetPosition(instanceId, ref, edge.ordinal(), value);
+  }
+
+  @Override
+  public void markDirty(String instanceId, String ref, boolean dirty) {
+    nativeMarkDirty(instanceId, ref, dirty);
+  }
+
+  @Override
+  public void setDeviceDisplay(String instanceId, float width, float height, float scale) {
+    nativeSetDeviceDisplay(instanceId, width, height, scale);
+  }
+
+  @Override
+  public void setStyleHeight(String instanceId, String ref, float value) {
+    nativeSetStyleHeight(instanceId, ref, value);
+  }
+
+  @Override
+  public void setInstanceRenderType(String instanceId, String renderType){
+    if(TextUtils.isEmpty(renderType)){
+       return;
+    }
+    nativeSetInstanceRenderType(instanceId, renderType);
+  }
+
+  @Override
+  public void setViewPortWidth(String instanceId,float viewPortWidth){
+    nativeSetViewPortWidth(instanceId,viewPortWidth);
+  }
+
+  @Override
+  public void removeInstanceRenderType(String instanceId){
+      nativeRemoveInstanceRenderType(instanceId);
+  }
+
+  @Override
+  public void setPageArgument(String instanceId, String key, String value){
+      nativeSetPageArgument(instanceId, key, value);
+  }
+
+  @Override
+  public void registerCoreEnv(String key, String value) {
+    nativeRegisterCoreEnv(key, value);
+  }
+
+  @CalledByNative
+  public void reportNativeInitStatus(String statusCode, String errorMsg) {
+    if (WXErrorCode.WX_JS_FRAMEWORK_INIT_SINGLE_PROCESS_SUCCESS.getErrorCode().equals(statusCode)
+            || WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED.getErrorCode().equals(statusCode)) {
+      IWXUserTrackAdapter userTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
+      if (userTrackAdapter != null) {
+        Map<String, Serializable> params = new HashMap<>(3);
+        params.put(IWXUserTrackAdapter.MONITOR_ERROR_CODE, statusCode);
+        params.put(IWXUserTrackAdapter.MONITOR_ARG, "InitFrameworkNativeError");
+        params.put(IWXUserTrackAdapter.MONITOR_ERROR_MSG, errorMsg);
+        WXLogUtils.e("reportNativeInitStatus is running and errorCode is " + statusCode + " And errorMsg is " + errorMsg);
+        userTrackAdapter.commit(null, null, IWXUserTrackAdapter.INIT_FRAMEWORK, null, params);
+      }
+
+      return;
+    }
+
+    if (WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL.getErrorCode().equals(statusCode)) {
+      WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL,
+              "WeexProxy::initFromParam()",
+              WXErrorCode.WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL.getErrorMsg() + ": " + errorMsg,
+              null);
+      return;
+    }
+
+    for (WXErrorCode e : WXErrorCode.values()) {
+      if (e.getErrorType().equals(WXErrorCode.ErrorType.NATIVE_ERROR)
+              && e.getErrorCode().equals(statusCode)) {
+        WXExceptionUtils.commitCriticalExceptionRT(null, e, "initFramework", errorMsg, null);
+        break;
+      }
+    }
+  }
+
+  public void fireEventOnDataRenderNode(String instanceId, String ref, String type, String data, String domChanges) {
+    nativeFireEventOnDataRenderNode(instanceId,ref,type,data, domChanges);
+  }
+
+  public void invokeCallbackOnDataRender(String instanceId, String callbackId, String data, boolean keepAlive) {
+    nativeInvokeCallbackOnDataRender(instanceId,callbackId,data, keepAlive);
+  }
+
+  public void registerModuleOnDataRenderNode(String data) {
+    nativeRegisterModuleOnDataRenderNode(data);
+  }
+
+  public void registerComponentOnDataRenderNode(String data) {
+    nativeRegisterComponentOnDataRenderNode(data);
+  }
+  public void reloadPageLayout(String instanceId){
+    nativeReloadPageLayout(instanceId);
+  }
+
+  public void setDeviceDisplayOfPage(String instanceId, float width, float height){
+    nativeSetDeviceDisplayOfPage(instanceId,width,height);
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXBridgeManager.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridgeManager.java
new file mode 100755
index 0000000..18da955
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridgeManager.java
@@ -0,0 +1,3684 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import static org.apache.weex.bridge.WXModuleManager.createDomModule;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Handler.Callback;
+import android.os.Looper;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.annotation.UiThread;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.Script;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.adapter.IWXJSExceptionAdapter;
+import org.apache.weex.adapter.IWXJsFileLoaderAdapter;
+import org.apache.weex.adapter.IWXJscProcessManager;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.common.IWXBridge;
+import org.apache.weex.common.IWXDebugConfig;
+import org.apache.weex.common.WXConfig;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXException;
+import org.apache.weex.common.WXJSBridgeMsgType;
+import org.apache.weex.common.WXJSExceptionInfo;
+import org.apache.weex.common.WXRefreshData;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.performance.WXStateRecord;
+import org.apache.weex.ui.WXComponentRegistry;
+import org.apache.weex.ui.WXRenderManager;
+import org.apache.weex.ui.action.ActionReloadPage;
+import org.apache.weex.ui.action.BasicGraphicAction;
+import org.apache.weex.ui.action.GraphicActionAddChildToRichtext;
+import org.apache.weex.ui.action.GraphicActionAddElement;
+import org.apache.weex.ui.action.GraphicActionAddEvent;
+import org.apache.weex.ui.action.GraphicActionAppendTreeCreateFinish;
+import org.apache.weex.ui.action.GraphicActionCreateBody;
+import org.apache.weex.ui.action.GraphicActionCreateFinish;
+import org.apache.weex.ui.action.GraphicActionLayout;
+import org.apache.weex.ui.action.GraphicActionMoveElement;
+import org.apache.weex.ui.action.GraphicActionRefreshFinish;
+import org.apache.weex.ui.action.GraphicActionRemoveChildFromRichtext;
+import org.apache.weex.ui.action.GraphicActionRemoveElement;
+import org.apache.weex.ui.action.GraphicActionRemoveEvent;
+import org.apache.weex.ui.action.GraphicActionRenderSuccess;
+import org.apache.weex.ui.action.GraphicActionUpdateAttr;
+import org.apache.weex.ui.action.GraphicActionUpdateRichtextAttr;
+import org.apache.weex.ui.action.GraphicActionUpdateRichtextStyle;
+import org.apache.weex.ui.action.GraphicActionUpdateStyle;
+import org.apache.weex.ui.action.GraphicPosition;
+import org.apache.weex.ui.action.GraphicSize;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.module.WXDomModule;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXFileUtils;
+import org.apache.weex.utils.WXJsonUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import org.apache.weex.utils.WXWsonJSONSwitch;
+import org.apache.weex.utils.batch.BactchExecutor;
+import org.apache.weex.utils.batch.Interceptor;
+import org.apache.weex.utils.tools.LogDetail;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Stack;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+/**
+ * Manager class for communication between JavaScript and Android.
+ * <ol>
+ * <li>
+ * Handle Android to JavaScript call, can be one of the following
+ * <ul>
+ * <li>{@link #createInstance(String, String, Map, String)}</li>
+ * <li>{@link #destroyInstance(String)}</li>
+ * <li>{@link #refreshInstance(String, WXRefreshData)}</li>
+ * <li>{@link #registerModules(Map)}</li>
+ * <li>{@link #registerComponents(List)}</li>
+ * <li>{@link #invokeCallJSBatch(Message)}</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Handle JavaScript to Android call
+ * </li>
+ * <li>
+ * Handle next tick of message.
+ * </li>
+ * </ol>
+ */
+public class WXBridgeManager implements Callback, BactchExecutor {
+
+  private static Class clazz_debugProxy = null;
+  public static final String METHOD_CREATE_INSTANCE = "createInstance";
+  public static final String METHOD_CREATE_PAGE_WITH_CONTENT = "CreatePageWithContent";
+  public static final String METHOD_UPDATE_COMPONENT_WITH_DATA = "UpdateComponentData";
+  private static final String METHOD_POST_TASK_TO_MSG_LOOP = "PostTaskToMsgLoop";
+  private static final String METHOD_JSFM_NOT_INIT_IN_EAGLE_MODE = "JsfmNotInitInEagleMode";
+  private static final String METHOD_MOVE_RENDER_OBJECT = "RenderPage::MoveRenderObject";
+  public static final String METHOD_DESTROY_INSTANCE = "destroyInstance";
+  public static final String METHOD_CALL_JS = "callJS";
+  public static final String METHOD_SET_TIMEOUT = "setTimeoutCallback";
+  public static final String METHOD_REGISTER_MODULES = "registerModules";
+  public static final String METHOD_REGISTER_COMPONENTS = "registerComponents";
+  public static final String METHOD_FIRE_EVENT = "fireEvent";
+  public static final String METHD_FIRE_EVENT_SYNC = "fireEventSync";
+  public static final String METHD_COMPONENT_HOOK_SYNC = "componentHook";
+  public static final String METHOD_CALLBACK = "callback";
+  public static final String METHOD_REFRESH_INSTANCE = "refreshInstance";
+  public static final String METHOD_FIRE_EVENT_ON_DATA_RENDER_NODE = "fireEventOnDataRenderNode";
+  public static final String METHOD_NOTIFY_TRIM_MEMORY = "notifyTrimMemory";
+  public static final String METHOD_NOTIFY_SERIALIZE_CODE_CACHE =
+          "notifySerializeCodeCache";
+  public static final String METHOD_CREATE_INSTANCE_CONTEXT = "createInstanceContext";
+
+  public static final String KEY_METHOD = "method";
+  public static final String KEY_ARGS = "args";
+
+  // args
+  public static final String COMPONENT = "component";
+  public static final String REF = "ref";
+  public static final String MODULE = "module";
+  public static final String METHOD = "method";
+  public static final String KEY_PARAMS = "params";
+  public static final String ARGS = "args";
+  public static final String OPTIONS = "options";
+  public static final String INITLOGFILE = "/jsserver_start.log";
+  private static final String NON_CALLBACK = "-1";
+  private static final String UNDEFINED = "undefined";
+  private static final String BUNDLE_TYPE = "bundleType";
+  private static final String RENDER_STRATEGY = "renderStrategy";
+  private static final int INIT_FRAMEWORK_OK = 1;
+  private static final int CRASHREINIT = 50;
+  static volatile WXBridgeManager mBridgeManager;
+  private static long LOW_MEM_VALUE = 120;
+  public volatile static int reInitCount = 1;
+  private volatile static int sInitFrameWorkCount = 0;
+  private static String crashUrl = null;
+  private static long lastCrashTime = 0;
+
+  private static String mRaxApi = null;
+//  private static String mRaxExtApi = null;
+
+  // add for clound setting, default value is true
+  // can use it to control weex sandbox
+  // if true will open weex sandbox for multi context
+  private volatile static boolean isSandBoxContext = true;
+
+  // add for cloud setting, default value is false.
+  // weexcore use single process or not
+  private static boolean isUseSingleProcess = false;
+  // add for cloud setting, default value is false.
+  // jsEngine use multiThread or not
+  private volatile static boolean isJsEngineMultiThreadEnable = false;
+
+  public enum BundType {
+    Vue,
+    Rax,
+    Others
+  };
+
+  private static final boolean BRIDGE_LOG_SWITCH = false;
+
+  /**
+   * Whether JS Framework(main.js) has been initialized.
+   */
+  private volatile static boolean mInit = false;
+
+  private static String globalConfig = "none";
+  private static String GLOBAL_CONFIG_KEY = "global_switch_config";
+
+  private static Map<String, String> mWeexCoreEnvOptions = new HashMap<>();
+
+  /**
+   * package
+   **/
+  Handler mJSHandler;
+  /**
+   * next tick tasks, can set priority
+   */
+  private WXHashMap<String, ArrayList<WXHashMap<String, Object>>> mNextTickTasks = new WXHashMap<>();
+  /**
+   * JSThread
+   */
+  private WXThread mJSThread;
+  private IWXBridge mWXBridge;
+  private Object mWxDebugProxy;
+
+  private boolean mMock = false;
+
+  private List<Map<String, Object>> mRegisterComponentFailList = new ArrayList<>(8);
+  private List<Map<String, Object>> mRegisterModuleFailList = new ArrayList<>(8);
+  private List<String> mRegisterServiceFailList = new ArrayList<>(8);
+  private HashSet<String> mDestroyedInstanceId = new HashSet<>();
+  private StringBuilder mLodBuilder = new StringBuilder(50);
+  private Interceptor mInterceptor;
+  private WXParams mInitParams;
+
+  private WXBridgeManager() {
+    initWXBridge(WXEnvironment.sRemoteDebugMode);
+    mJSThread = new WXThread("WeexJSBridgeThread", this);
+    mJSHandler = mJSThread.getHandler();
+  }
+
+  public static WXBridgeManager getInstance() {
+    if (mBridgeManager == null) {
+      synchronized (WXBridgeManager.class) {
+        if (mBridgeManager == null) {
+          mBridgeManager = new WXBridgeManager();
+        }
+      }
+    }
+    return mBridgeManager;
+  }
+
+  public void setUseSingleProcess(final boolean flag) {
+    if (flag != isUseSingleProcess) {
+      isUseSingleProcess = flag;
+//      //we should reinit framework if js framework has been initialized
+//      if (isJSFrameworkInit()) {
+//        if (isJSThread()) {
+//          WXSDKEngine.reload();
+//        } else {
+//          post(new Runnable() {
+//            @Override
+//            public void run() {
+//              WXSDKEngine.reload();
+//            }
+//          });
+//        }
+//      }
+    }
+  }
+
+  public void onInteractionTimeUpdate(final String instanceId){
+    post(new Runnable() {
+      @Override
+      public void run() {
+        if (mWXBridge instanceof WXBridge ){
+          ((WXBridge)mWXBridge).nativeOnInteractionTimeUpdate(instanceId);
+        }
+      }
+    });
+  }
+
+  public boolean jsEngineMultiThreadEnable() {
+    return isJsEngineMultiThreadEnable;
+  }
+
+  public void checkJsEngineMultiThread() {
+    boolean flag = false;
+    IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
+    if(wxJscProcessManager!=null) {
+      flag = wxJscProcessManager.enableBackupThread();
+    }
+
+    if(flag == WXBridgeManager.isJsEngineMultiThreadEnable) {
+        return;
+    }
+
+    WXBridgeManager.isJsEngineMultiThreadEnable = flag;
+    //we should reinit framework if js framework has been initialized
+    if (isJSFrameworkInit()) {
+      if (isJSThread()) {
+        WXSDKEngine.reload();
+      } else {
+        post(new Runnable() {
+          @Override
+          public void run() {
+            WXSDKEngine.reload();
+          }
+        });
+      }
+    }
+  }
+  public void setSandBoxContext(final boolean flag) {
+    if (flag != isSandBoxContext) {
+      isSandBoxContext = flag;
+      // use diff context reinit jsf
+      if (isJSThread()) {
+
+        setJSFrameworkInit(false);
+        WXModuleManager.resetAllModuleState();
+        String jsf = "";
+        if (!isSandBoxContext) {
+          jsf = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
+        } else {
+          jsf = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
+        }
+        initFramework(jsf);
+        WXServiceManager.reload();
+        WXModuleManager.reload();
+        WXComponentRegistry.reload();
+      } else {
+        post(new Runnable() {
+          @Override
+          public void run() {
+            setJSFrameworkInit(false);
+            WXModuleManager.resetAllModuleState();
+            String jsf = "";
+            if (!isSandBoxContext) {
+              jsf = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
+            } else {
+              jsf = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
+            }
+            initFramework(jsf);
+            WXServiceManager.reload();
+            WXModuleManager.reload();
+            WXComponentRegistry.reload();
+          }
+        });
+      }
+    }
+  }
+
+  // setJSFrameworkInit and isJSFrameworkInit may use on diff thread
+  // use volatile
+  @RestrictTo(Scope.LIBRARY)
+  boolean isJSFrameworkInit() {
+    return mInit;
+  }
+
+  private void setJSFrameworkInit(boolean init) {
+    mInit = init;
+    WXStateRecord.getInstance().recoreJsfmInitHistory("setJsfmInitFlag:"+init);
+    if (init == true) {
+      onJsFrameWorkInitSuccees();
+    }
+  }
+
+  private void initWXBridge(boolean remoteDebug) {
+    if (remoteDebug && WXEnvironment.isApkDebugable()) {
+      WXEnvironment.sDebugServerConnectable = true;
+    }
+
+    if (WXEnvironment.sDebugServerConnectable && (WXEnvironment.isApkDebugable() || WXEnvironment.sForceEnableDevTool)) {
+      if (WXEnvironment.getApplication() != null) {
+        try {
+          if (clazz_debugProxy == null) {
+            clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
+          }
+          if (clazz_debugProxy != null) {
+            Constructor constructor = clazz_debugProxy.getConstructor(Context.class, IWXDebugConfig.class);
+            if (constructor != null) {
+              mWxDebugProxy = constructor.newInstance(WXEnvironment.getApplication(),
+                      new IWXDebugConfig() {
+                        @Override
+                        public WXBridgeManager getWXJSManager() {
+                          return WXBridgeManager.this;
+                        }
+
+                        @Override
+                        public WXDebugJsBridge getWXDebugJsBridge() {
+                          return new WXDebugJsBridge();
+                        }
+                      });
+              if (mWxDebugProxy != null) {
+                Method method_start = clazz_debugProxy.getMethod("start");
+                if (method_start != null) {
+                  method_start.invoke(mWxDebugProxy);
+                }
+              }
+            }
+          }
+        } catch (Throwable e) {
+          //Ignore, It will throw Exception on Release environment
+        }
+        WXServiceManager.execAllCacheJsService();
+      } else {
+        WXLogUtils.e("WXBridgeManager", "WXEnvironment.sApplication is null, skip init Inspector");
+      }
+    }
+    if (remoteDebug && mWxDebugProxy != null) {
+      try {
+        if (clazz_debugProxy == null ) {
+          clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
+        }
+        if (clazz_debugProxy != null) {
+          Method method_getWXBridge = clazz_debugProxy.getMethod("getWXBridge");
+          if (method_getWXBridge != null) {
+            mWXBridge = (IWXBridge) method_getWXBridge.invoke(mWxDebugProxy);
+          }
+        }
+      } catch (Throwable e) {
+        //Ignore, It will throw Exception on Release environment
+      }
+    } else {
+      mWXBridge = new WXBridge();
+    }
+  }
+
+  public String dumpIpcPageInfo(){
+    if (mWXBridge instanceof WXBridge){
+      return ((WXBridge)mWXBridge).nativeDumpIpcPageQueueInfo();
+    }
+    return "";
+  }
+
+  public boolean isRebootExceedLimit(){
+    return reInitCount > CRASHREINIT;
+  }
+
+  public void stopRemoteDebug() {
+    if (mWxDebugProxy != null) {
+      try {
+        if (clazz_debugProxy == null) {
+          clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
+        }
+        if (clazz_debugProxy != null) {
+          Method method_stop = clazz_debugProxy.getMethod("stop", boolean.class);
+          if (method_stop != null) {
+            method_stop.invoke(mWxDebugProxy, true);
+          }
+        }
+      } catch (Throwable e) {
+        //Ignore, It will throw Exception on Release environment
+      }
+    }
+  }
+
+  public Object callModuleMethod(String instanceId, String moduleStr, String methodStr, JSONArray args) {
+    return callModuleMethod(instanceId, moduleStr, methodStr, args, null);
+  }
+
+  public Object callModuleMethod(String instanceId, String moduleStr, String methodStr, JSONArray args, JSONObject options) {
+    WXSDKInstance wxsdkInstance = WXSDKManager.getInstance()
+            .getSDKInstance(instanceId);
+    if (wxsdkInstance == null) {
+      return null;
+    }
+    if (wxsdkInstance.isNeedValidate()
+            && WXSDKManager.getInstance().getValidateProcessor() != null) {
+      WXValidateProcessor.WXModuleValidateResult validateResult = WXSDKManager
+              .getInstance().getValidateProcessor()
+              .onModuleValidate(wxsdkInstance, moduleStr, methodStr, args, options);
+      if (validateResult == null) {
+        return null;
+      }
+      if (validateResult.isSuccess) {
+        return WXModuleManager.callModuleMethod(instanceId, moduleStr, methodStr,
+                args);
+      } else {
+        JSONObject validateInfo = validateResult.validateInfo;
+        if (validateInfo != null) {
+          WXLogUtils.e("[WXBridgeManager] module validate fail. >>> " + validateInfo.toJSONString());
+        }
+        return validateInfo;
+      }
+    }
+    try {
+      return WXModuleManager.callModuleMethod(instanceId, moduleStr, methodStr, args);
+    }catch(NumberFormatException e){
+      ArrayMap<String, String> ext = new ArrayMap<>();
+      ext.put("moduleName", moduleStr);
+      ext.put("methodName", methodStr);
+      ext.put("args", args.toJSONString());
+      WXLogUtils.e("[WXBridgeManager] callNative : numberFormatException when parsing string to numbers in args", ext.toString());
+      return null;
+    }
+  }
+
+  /**
+   * Model switch. For now, debug model and release model are supported
+   */
+  public void restart() {
+    setJSFrameworkInit(false);
+    WXModuleManager.resetAllModuleState();
+    initWXBridge(WXEnvironment.sRemoteDebugMode);
+    mWXBridge.resetWXBridge(WXEnvironment.sRemoteDebugMode);
+  }
+
+  /**
+   * Set current Instance
+   *
+   * @param instanceId {@link WXSDKInstance#mInstanceId}
+   */
+  public synchronized void setStackTopInstance(final String instanceId) {
+    post(new Runnable() {
+
+      @Override
+      public void run() {
+        mNextTickTasks.setStackTopInstance(instanceId);
+      }
+    },instanceId, null, null);
+  }
+
+  @Override
+  public void post(Runnable r) {
+      postWithName(r,null,null);
+  }
+
+  public void postWithName(Runnable r, WXSDKInstance instance, String runnableName) {
+   Runnable secure = WXThread.secure(r,instance, runnableName);
+    if (mInterceptor != null && mInterceptor.take(secure)) {
+      //task is token by the interceptor
+      return;
+    }
+    if (mJSHandler == null) {
+      return;
+    }
+
+    mJSHandler.post(secure);
+  }
+
+  @Override
+  public void setInterceptor(Interceptor interceptor) {
+    mInterceptor = interceptor;
+  }
+
+  public void post(Runnable r, Object token, WXSDKInstance instance, String runnableName) {
+    if (mJSHandler == null) {
+      return;
+    }
+
+    Message m = Message.obtain(mJSHandler, WXThread.secure(r, instance, runnableName));
+    m.obj = token;
+    m.sendToTarget();
+  }
+
+  public void post(Runnable r, Object token) {
+    post(r, token, null, null);
+  }
+
+  public void postDelay(Runnable r,long delayMillis){
+    if (mJSHandler == null) {
+      return;
+    }
+    mJSHandler.postDelayed(WXThread.secure(r),delayMillis);
+  }
+
+  void setTimeout(String callbackId, String time) {
+    Message message = Message.obtain();
+    message.what = WXJSBridgeMsgType.SET_TIMEOUT;
+    TimerInfo timerInfo = new TimerInfo();
+    timerInfo.callbackId = callbackId;
+    timerInfo.time = (long) Float.parseFloat(time);
+    message.obj = timerInfo;
+
+    mJSHandler.sendMessageDelayed(message, timerInfo.time);
+  }
+
+  public void sendMessageDelayed(Message message, long delayMillis) {
+    if (message == null || mJSHandler == null || mJSThread == null
+            || !mJSThread.isWXThreadAlive() || mJSThread.getLooper() == null) {
+      return;
+    }
+    mJSHandler.sendMessageDelayed(message, delayMillis);
+  }
+
+  public void removeMessage(int what, Object obj) {
+    if (mJSHandler == null || mJSThread == null
+            || !mJSThread.isWXThreadAlive() || mJSThread.getLooper() == null) {
+      return;
+    }
+    mJSHandler.removeMessages(what, obj);
+  }
+
+  public Object callNativeModule(String instanceId, String module, String method, JSONArray arguments, Object options) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(module) || TextUtils.isEmpty(method)) {
+      WXLogUtils.d("[WXBridgeManager] call callNativeModule arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeModule",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> instanceId:").append(instanceId)
+              .append(", module:").append(module).append(", method:").append(method).append(", arguments:").append(arguments);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    try {
+      if (WXDomModule.WXDOM.equals(module)) {
+        WXDomModule dom = WXModuleManager.getDomModule(instanceId);
+        return dom.callDomMethod(method, arguments);
+      } else {
+        return callModuleMethod(instanceId, module,
+              method, arguments);
+      }
+    } catch (Exception e) {
+      String err = "[WXBridgeManager] callNative exception: " + WXLogUtils.getStackTrace(e);
+      WXLogUtils.e(err);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNativeModule",
+              err, null);
+    }
+
+    return null;
+  }
+
+  public Object callNativeModule(String instanceId, String module, String method, JSONArray arguments, JSONObject options) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(module) || TextUtils.isEmpty(method)) {
+      WXLogUtils.d("[WXBridgeManager] call callNativeModule arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeModule",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> instanceId:").append(instanceId)
+              .append(", module:").append(module).append(", method:").append(method).append(", arguments:").append(arguments);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    try {
+      if (WXDomModule.WXDOM.equals(module)) {
+        WXDomModule dom = WXModuleManager.getDomModule(instanceId);
+        if(dom != null){
+          return dom.callDomMethod(method, arguments);
+        } else {
+          createDomModule(WXSDKManager.getInstance().getSDKInstance(instanceId));
+        }
+      } else {
+        return callModuleMethod(instanceId, module,
+              method, arguments, options);
+      }
+    } catch (Exception e) {
+      String err = "[WXBridgeManager] callNativeModule exception: " + WXLogUtils.getStackTrace(e);
+      WXLogUtils.e(err);
+    }
+
+    return null;
+  }
+
+  public Object callNativeComponent(String instanceId, String componentRef, String method, JSONArray arguments, Object options) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(componentRef) || TextUtils.isEmpty(method)) {
+      WXLogUtils.d("[WXBridgeManager] call callNativeComponent arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeComponent",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callNativeComponent >>>> instanceId:").append(instanceId)
+              .append(", componentRef:").append(componentRef).append(", method:").append(method).append(", arguments:").append(arguments);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    try {
+      WXDomModule dom = WXModuleManager.getDomModule(instanceId);
+      if (null != dom){
+        dom.invokeMethod(componentRef, method, arguments);
+      }else {
+        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+        if(null == instance || !instance.isDestroy()){
+          WXLogUtils.e("WXBridgeManager","callNativeComponent exception :null == dom ,method:"+method);
+        }
+      }
+
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callNativeComponent exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNativeComponent",
+              WXLogUtils.getStackTrace(e), null);
+    }
+    return null;
+  }
+
+  /**
+   * Dispatch the native task to be executed.
+   *
+   * @param instanceId {@link WXSDKInstance#mInstanceId}
+   * @param tasks      tasks to be executed
+   * @param callback   next tick id
+   */
+  public int callNative(String instanceId, JSONArray tasks, String callback) {
+
+    if (TextUtils.isEmpty(instanceId) || tasks == null) {
+      WXLogUtils.d("[WXBridgeManager] call callNative arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNative",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callNative >>>> instanceId:").append(instanceId)
+              .append(", tasks:").append(tasks).append(", callback:").append(callback);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+
+    long parseNanos = System.nanoTime();
+    JSONArray array = tasks;
+    parseNanos = System.nanoTime() - parseNanos;
+
+    if (null != array && array.size() > 0) {
+      int size = array.size();
+      try {
+        JSONObject task;
+        for (int i = 0; i < size; ++i) {
+          task = (JSONObject) array.get(i);
+          if (task != null && WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
+            Object module = task.get(MODULE);
+            if (module != null) {
+              if (WXDomModule.WXDOM.equals(module)) {
+                WXDomModule dom = WXModuleManager.getDomModule(instanceId);
+                dom.callDomMethod(task, parseNanos);
+              } else {
+                JSONObject optionObj = task.getJSONObject(OPTIONS);
+                WXStateRecord.getInstance().recordAction(instanceId,"callModuleMethod:"+instanceId+","+module+","+task.get(METHOD));
+                callModuleMethod(instanceId, (String) module,
+                        (String) task.get(METHOD), (JSONArray) task.get(ARGS), optionObj);
+              }
+            } else if (task.get(COMPONENT) != null) {
+              WXDomModule dom = WXModuleManager.getDomModule(instanceId);
+              WXStateRecord.getInstance().recordAction(instanceId,"callDomMethod:"+instanceId+","+task.get(METHOD));
+              dom.invokeMethod((String) task.get(REF), (String) task.get(METHOD), (JSONArray) task.get(ARGS));
+            } else {
+              throw new IllegalArgumentException("unknown callNative");
+            }
+          }
+        }
+      } catch (Exception e) {
+        WXLogUtils.e("[WXBridgeManager] callNative exception: ", e);
+        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNative",
+                WXLogUtils.getStackTrace(e) , null);
+      }
+    }
+
+    if (UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+    // get next tick
+    getNextTick(instanceId, callback);
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  // callUpdateFinish
+  public int callUpdateFinish(String instanceId, String callback) {
+
+    if (TextUtils.isEmpty(instanceId)) {
+      WXLogUtils.d("[WXBridgeManager] call callUpdateFinish arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateFinish",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callUpdateFinish >>>> instanceId:").append(instanceId)
+              .append(", callback:").append(callback);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callUpdateFinish exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateFinish",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    if (callback == null || callback.isEmpty() || UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+    // get next tick
+    getNextTick(instanceId, callback);
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  // callRefreshFinish
+  public int callRefreshFinish(String instanceId, String callback) {
+
+    if (TextUtils.isEmpty(instanceId)) {
+      WXLogUtils.d("[WXBridgeManager] call callRefreshFinish arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRefreshFinish",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callRefreshFinish >>>> instanceId:").append(instanceId)
+              .append(", callback:").append(callback);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+        if (instance != null) {
+          GraphicActionRefreshFinish action = new GraphicActionRefreshFinish(instance);
+          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
+        }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callRefreshFinish exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRefreshFinish",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    if (UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+    // get next tick
+    getNextTick(instanceId, callback);
+    return IWXBridge.INSTANCE_RENDERING;
+
+  }
+
+  public int callReportCrashReloadPage(String instanceId, String crashFile) {
+    boolean isCrashFileEmpty = TextUtils.isEmpty(crashFile);
+    try {
+      String url = null;
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        url = instance.getBundleUrl();
+        instance.setHasException(true);
+      }
+      Map<String,String> extInfo = new HashMap<>(2);
+      extInfo.put("weexCoreThreadStackTrace:",WXBridgeManager.getInstance().getWeexCoreThreadStackTrace());
+      extInfo.put("wxStateInfo",WXStateRecord.getInstance().getStateInfo().toString());
+
+      if(!isCrashFileEmpty) {
+        try {
+            if (WXEnvironment.getApplication() != null) {
+                crashFile = mInitParams.getCrashFilePath() + crashFile;
+                Log.d("jsengine", "callReportCrashReloadPage crashFile:" + crashFile);
+            }
+        } catch (Throwable e) {
+          WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+        WXStateRecord.getInstance().onJSCCrash(TextUtils.isEmpty(instanceId)?"null":instanceId);
+        callReportCrash(crashFile, instanceId, url,extInfo);
+      } else {
+        WXStateRecord.getInstance().onJSEngineReload(TextUtils.isEmpty(instanceId)?"null":instanceId);
+         commitJscCrashAlarmMonitor(IWXUserTrackAdapter.JS_BRIDGE, WXErrorCode.WX_ERR_RELOAD_PAGE, "reboot jsc Engine", instanceId, url,extInfo);
+      }
+
+      WXLogUtils.e("reInitCount:"+reInitCount);
+
+      if (reInitCount > CRASHREINIT) {
+        WXExceptionUtils.commitCriticalExceptionRT("jsEngine", WXErrorCode.WX_ERR_RELOAD_PAGE_EXCEED_LIMIT,
+            "callReportCrashReloadPage","reInitCount:"+reInitCount,extInfo);
+        return IWXBridge.INSTANCE_RENDERING_ERROR;
+      }
+      reInitCount++;
+      // reinit frame work
+      setJSFrameworkInit(false);
+      WXModuleManager.resetAllModuleState();
+      initScriptsFramework("");
+
+      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+        return IWXBridge.DESTROY_INSTANCE;
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callReportCrashReloadPage exception: ", e);
+    }
+    try {
+
+      if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
+        boolean reloadThisInstance = shouldReloadCurrentInstance(
+                WXSDKManager.getInstance().getSDKInstance(instanceId).getBundleUrl());
+        new ActionReloadPage(instanceId, reloadThisInstance).executeAction();
+      }
+
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callReloadPage exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callReportCrashReloadPage",
+              WXLogUtils.getStackTrace(e), null);
+    }
+    return IWXBridge.INSTANCE_RENDERING_ERROR;
+  }
+
+  public boolean shouldReloadCurrentInstance(String aUrl) {
+    long time = System.currentTimeMillis();
+    String bizUrl = aUrl;
+    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+    if (adapter != null) {
+        boolean check_biz_url = Boolean.parseBoolean(adapter
+                .getConfig("android_weex_ext_config",
+                        "check_biz_url",
+                        "true"));
+        WXLogUtils.e("check_biz_url : " + check_biz_url);
+        if(check_biz_url && !TextUtils.isEmpty(aUrl)) {
+            Uri uri = Uri.parse(aUrl);
+            if(uri != null) {
+                bizUrl = uri.buildUpon().clearQuery().build().toString();
+            }
+        }
+    }
+
+    if (crashUrl == null ||
+            (crashUrl != null && !crashUrl.equals(bizUrl)) ||
+            ((time - lastCrashTime) > 15000)) {
+      crashUrl = bizUrl;
+      lastCrashTime = time;
+      return true;
+    }
+    lastCrashTime = time;
+    return false;
+  }
+
+  public void callReportCrash(String crashFile, final String instanceId, final String url,final Map<String,String> extInfo) {
+    // statistic weex core process crash
+    Date date = new Date();
+    DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
+    String time = format.format(date);
+    final String origin_filename = crashFile + "." + time;
+    File oldfile = new File(crashFile);
+    File newfile = new File(origin_filename);
+    if (oldfile.exists()) {
+      oldfile.renameTo(newfile);
+    }
+    Thread t = new Thread(new Runnable() {
+      public void run() {
+        try {
+          File file = new File(origin_filename);
+          if (file.exists()) {
+            if (file.length() > 0) {
+              StringBuilder result = new StringBuilder();
+              try {
+                BufferedReader br = new BufferedReader(new FileReader(origin_filename));
+                String s = null;
+                // boolean foundStart = false;
+                while ((s = br.readLine()) != null) {
+                  if ("".equals(s)) {
+                    continue;
+                  }
+                  // if (("r0:").equals(s)) {
+                  //  break;
+                  // }
+                  result.append(s + "\n");
+                }
+                commitJscCrashAlarmMonitor(IWXUserTrackAdapter.JS_BRIDGE, WXErrorCode.WX_ERR_JSC_CRASH, result.toString(), instanceId, url,extInfo);
+                br.close();
+              } catch (Exception e) {
+                WXLogUtils.e(WXLogUtils.getStackTrace(e));
+              }
+            } else {
+              WXLogUtils.e("[WXBridgeManager] callReportCrash crash file is empty");
+            }
+            if(!WXEnvironment.isApkDebugable())
+              file.delete();
+          }
+        } catch (Throwable throwable) {
+          WXLogUtils.e("[WXBridgeManager] callReportCrash exception: ", throwable);
+        }
+      }
+    });
+    t.start();
+  }
+
+  private void getNextTick(final String instanceId, final String callback) {
+    addJSTask(METHOD_CALLBACK, instanceId, callback, "{}");
+    sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
+  }
+
+  private void getNextTick(final String instanceId) {
+    addJSTask(METHOD_CALLBACK, instanceId, "", "{}");
+    sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
+  }
+
+  public String syncExecJsOnInstanceWithResult(final String instanceId, final String js, final int type) {
+    final CountDownLatch waitLatch = new CountDownLatch(1);
+    EventResult callback = new EventResult(){
+      @Override
+      public void onCallback(Object result) {
+        super.onCallback(result);
+        waitLatch.countDown();
+      }
+    };
+    try{
+      execJSOnInstance(callback, instanceId, js, type);
+      waitLatch.await(100, TimeUnit.MILLISECONDS);
+      if (callback != null && callback.getResult() != null) {
+        return  callback.getResult().toString();
+      }
+      return "";
+    }catch (Throwable e){
+      WXLogUtils.e("syncCallExecJsOnInstance", e);
+      return  "";
+    }
+  }
+
+  public void loadJsBundleInPreInitMode(final String instanceId, final String js){
+    post(new Runnable() {
+      @Override
+      public void run() {
+        invokeExecJSOnInstance(instanceId, js, -1);
+        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+        if (null != instance && instance.isPreInitMode()){
+          instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
+          instance.getApmForInstance().onStageWithTime(WXInstanceApm.KEY_PAGE_STAGES_END_EXCUTE_BUNDLE,WXUtils.getFixUnixTime()+600);
+        }
+      }
+    });
+  }
+
+  /**
+   * ref, type, data, domChanges
+   * */
+  public EventResult syncCallJSEventWithResult(final String method, final String instanceId, final List<Object> params, final Object... args) {
+    final CountDownLatch waitLatch = new CountDownLatch(1);
+    EventResult callback = new EventResult(){
+      @Override
+      public void onCallback(Object result) {
+        super.onCallback(result);
+        waitLatch.countDown();
+      }
+    };
+    try{
+      asyncCallJSEventWithResult(callback, method, instanceId, params, args);
+      waitLatch.await(100, TimeUnit.MILLISECONDS);
+      return  callback;
+    }catch (Exception e){
+      WXLogUtils.e("syncCallJSEventWithResult", e);
+      return  callback;
+    }
+  }
+
+  public void asyncCallJSEventVoidResult(final String method, final String instanceId, final List<Object> params, final Object... args) {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        try{
+          if (args == null || args.length == 0) {
+            return;
+          }
+
+          ArrayList<Object> argsList = new ArrayList<>();
+          for (Object arg : args) {
+            argsList.add(arg);
+          }
+          if (params != null) {
+            ArrayMap map = new ArrayMap(4);
+            map.put(KEY_PARAMS, params);
+            argsList.add(map);
+          }
+
+          WXHashMap<String, Object> task = new WXHashMap<>();
+          task.put(KEY_METHOD, method);
+          task.put(KEY_ARGS, argsList);
+          Object[] tasks = {task};
+          WXJSObject[] jsArgs = {
+                  new WXJSObject(WXJSObject.String, instanceId),
+                  WXWsonJSONSwitch.toWsonOrJsonWXJSObject(tasks)};
+          invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, jsArgs, true);
+          jsArgs[0] = null;
+          jsArgs = null;
+        }catch (Exception e){
+          WXLogUtils.e("asyncCallJSEventVoidResult" , e);
+        }
+      }
+    });
+  }
+
+  /**
+   * aync call js event and return result in eventResult callback
+   * */
+  private void asyncCallJSEventWithResult(final EventResult eventCallback, final String method, final String instanceId, final List<Object> params, final Object... args) {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        Object result = null;
+        try{
+          if (args == null || args.length == 0) {
+            return;
+          }
+
+          ArrayList<Object> argsList = new ArrayList<>();
+          for (Object arg : args) {
+            argsList.add(arg);
+          }
+          if (params != null) {
+            ArrayMap map = new ArrayMap(4);
+            map.put(KEY_PARAMS, params);
+            argsList.add(map);
+          }
+
+          WXHashMap<String, Object> task = new WXHashMap<>();
+          task.put(KEY_METHOD, method);
+          task.put(KEY_ARGS, argsList);
+          Object[] tasks = {task};
+          WXJSObject[] jsArgs = {
+                  new WXJSObject(WXJSObject.String, instanceId),
+                  WXWsonJSONSwitch.toWsonOrJsonWXJSObject(tasks)};
+          ResultCallback<byte[]> resultCallback = null;
+          if (eventCallback != null) {
+            resultCallback = new ResultCallback<byte[]>() {
+              @Override
+              public void onReceiveResult(byte[] result) {
+                JSONArray arrayResult = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(result);
+                if(arrayResult != null && arrayResult.size() > 0){
+                  eventCallback.onCallback(arrayResult.get(0));
+                }
+              }
+            };
+          }
+          invokeExecJSWithCallback(String.valueOf(instanceId), null, METHOD_CALL_JS,
+                  jsArgs, resultCallback, true);
+          jsArgs[0] = null;
+        }catch (Exception e){
+          WXLogUtils.e("asyncCallJSEventWithResult" , e);
+        }
+      }
+    });
+  }
+
+  private void addJSEventTask(final String method, final String instanceId, final List<Object> params, final Object... args) {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        if (args == null || args.length == 0) {
+          return;
+        }
+
+        ArrayList<Object> argsList = new ArrayList<>();
+        for (Object arg : args) {
+          argsList.add(arg);
+        }
+        if (params != null) {
+          ArrayMap map = new ArrayMap(4);
+          map.put(KEY_PARAMS, params);
+          argsList.add(map);
+        }
+
+        WXHashMap<String, Object> task = new WXHashMap<>();
+        task.put(KEY_METHOD, method);
+        task.put(KEY_ARGS, argsList);
+
+
+        if (mNextTickTasks.get(instanceId) == null) {
+          ArrayList<WXHashMap<String, Object>> list = new ArrayList<>();
+          list.add(task);
+          mNextTickTasks.put(instanceId, list);
+        } else {
+          mNextTickTasks.get(instanceId).add(task);
+        }
+      }
+    });
+  }
+
+  private void addJSTask(final String method, final String instanceId, final Object... args) {
+    addJSEventTask(method, instanceId, null, args);
+  }
+
+  private void sendMessage(String instanceId, int what) {
+    Message msg = Message.obtain(mJSHandler);
+    msg.obj = instanceId;
+    msg.what = what;
+    msg.sendToTarget();
+  }
+
+  /**
+   * Initialize JavaScript framework
+   *
+   * @param framework String representation of the framework to be init.
+   */
+  public synchronized void initScriptsFramework(String framework) {
+    Message msg = mJSHandler.obtainMessage();
+    msg.obj = framework;
+    msg.what = WXJSBridgeMsgType.INIT_FRAMEWORK;
+    msg.setTarget(mJSHandler);
+    msg.sendToTarget();
+  }
+
+  @Deprecated
+  public void fireEvent(final String instanceId, final String ref,
+                        final String type, final Map<String, Object> data) {
+    this.fireEvent(instanceId, ref, type, data, null);
+  }
+
+  /**
+   * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
+   *
+   * @param instanceId
+   * @param ref
+   * @param type
+   * @param data
+   * @param domChanges
+   */
+  @Deprecated
+  public void fireEvent(final String instanceId, final String ref,
+                        final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
+    fireEventOnNode(instanceId, ref, type, data, domChanges);
+  }
+
+  /**
+   * Notify the JavaScript about the event happened on Android
+   */
+  public void fireEventOnNode(final String instanceId, final String ref,
+                              final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
+    fireEventOnNode(instanceId, ref, type, data, domChanges, null, null);
+  }
+
+  /**
+   * Notify the JavaScript about the event happened on Android
+   */
+  public void fireEventOnNode(final String instanceId, final String ref,
+                              final String type, final Map<String, Object> data,
+                              final Map<String, Object> domChanges, List<Object> params){
+    fireEventOnNode(instanceId, ref, type, data, domChanges, params, null);
+  }
+
+  public void fireEventOnNode(final String instanceId, final String ref,
+                              final String type, final Map<String, Object> data,
+                              final Map<String, Object> domChanges, List<Object> params,  EventResult callback) {
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)
+            || TextUtils.isEmpty(type) || mJSHandler == null) {
+      return;
+    }
+    if (!checkMainThread()) {
+      throw new WXRuntimeException(
+              "fireEvent must be called by main thread");
+    }
+    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+    if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER ||
+            instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
+      fireEventOnDataRenderNode(instanceId, ref, type, data, domChanges);
+    } else {
+      if(callback == null) {
+        addJSEventTask(METHOD_FIRE_EVENT, instanceId, params, ref, type, data, domChanges);
+        sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
+      }else{
+        asyncCallJSEventWithResult(callback, METHD_FIRE_EVENT_SYNC, instanceId, params, ref, type, data, domChanges);
+      }
+    }
+  }
+
+  private void fireEventOnDataRenderNode(final String instanceId, final String ref,
+                                         final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
+    mJSHandler.postDelayed(WXThread.secure(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+          long start = System.currentTimeMillis();
+          if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d("fireEventOnDataRenderNode >>>> instanceId:" + instanceId
+                + ", data:" + data);
+          }
+          if (mWXBridge instanceof WXBridge) {
+            ((WXBridge) mWXBridge).fireEventOnDataRenderNode(instanceId, ref, type,
+                (data == null || data.isEmpty()) ? "{}" : JSON.toJSONString(data),
+                (domChanges == null || domChanges.isEmpty()) ? "{}" : JSON.toJSONString(domChanges));
+          }
+          WXLogUtils.renderPerformanceLog("fireEventOnDataRenderNode", System.currentTimeMillis() - start);
+        } catch (Throwable e) {
+          String err = "[WXBridgeManager] fireEventOnDataRenderNode " + WXLogUtils.getStackTrace(e);
+          WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "fireEventOnDataRenderNode",
+              err, null);
+          WXLogUtils.e(err);
+        }
+      }
+    }), 0);
+  }
+
+  private boolean checkMainThread() {
+    return Looper.myLooper() == Looper.getMainLooper();
+  }
+
+
+  /**
+   * Invoke JavaScript callback. Use {@link JSCallback} instead.
+   *
+   * @see #callback(String, String, String)
+   */
+  @Deprecated
+  public void callback(String instanceId, String callback, String data) {
+    callback(instanceId, callback, data, false);
+  }
+
+  /**
+   * Invoke JavaScript callback. Use {@link JSCallback} instead.
+   */
+  @Deprecated
+  public void callback(final String instanceId, final String callback,
+                       final Map<String, Object> data) {
+    callback(instanceId, callback, data, false);
+  }
+
+  /**
+   * Use {@link JSCallback} instead.
+   *
+   * @param instanceId Weex Instance Id
+   * @param callback   callback referenece handle
+   * @param data       callback data
+   * @param keepAlive  if keep callback instance alive for later use
+   */
+  @Deprecated
+  public void callback(final String instanceId, final String callback,
+                       final Object data, boolean keepAlive) {
+    callbackJavascript(instanceId, callback, data, keepAlive);
+  }
+
+  /**
+   * Callback to Javascript function.
+   *
+   * @param instanceId Weex Instance Id
+   * @param callback   callback referenece handle
+   * @param data       callback data
+   * @param keepAlive  if keep callback instance alive for later use
+   */
+  void callbackJavascript(final String instanceId, final String callback,
+                          final Object data, boolean keepAlive) {
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(callback)
+            || mJSHandler == null) {
+      return;
+    }
+
+    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+    if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
+      callbackJavascriptOnDataRender(instanceId, callback, data, keepAlive);
+    } else {
+      addJSTask(METHOD_CALLBACK, instanceId, callback, data, keepAlive);
+      sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
+    }
+  }
+
+  void callbackJavascriptOnDataRender(final String instanceId, final String callback, final Object data, final boolean keepAlive){
+    mJSHandler.postDelayed(WXThread.secure(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          long start = System.currentTimeMillis();
+          String data_str = JSON.toJSONString(data);
+          if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d("callbackJavascriptOnDataRender >>>> instanceId:" + instanceId
+                + ", data:" + data_str);
+          }
+          if (mWXBridge instanceof WXBridge) {
+            ((WXBridge) mWXBridge).invokeCallbackOnDataRender(instanceId, callback,data_str ,keepAlive);
+          }
+          WXLogUtils.renderPerformanceLog("callbackJavascriptOnDataRender", System.currentTimeMillis() - start);
+        } catch (Throwable e) {
+          String err = "[WXBridgeManager] callbackJavascriptOnDataRender " + WXLogUtils.getStackTrace(e);
+          WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callbackJavascriptOnDataRender",
+              err, null);
+          WXLogUtils.e(err);
+        }
+      }
+    }), 0);
+  }
+
+  /**
+   * Refresh instance
+   */
+  public void refreshInstance(final String instanceId, final WXRefreshData jsonData) {
+    if (TextUtils.isEmpty(instanceId) || jsonData == null) {
+      return;
+    }
+    mJSHandler.postDelayed(WXThread.secure(new Runnable() {
+      @Override
+      public void run() {
+        invokeRefreshInstance(instanceId, jsonData);
+      }
+    }), 0);
+  }
+
+  private void invokeRefreshInstance(String instanceId, WXRefreshData refreshData) {
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (!isSkipFrameworkInit(instanceId) && !isJSFrameworkInit()) {
+        if (instance != null) {
+          instance.onRenderError(
+                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg()
+                          + "invokeRefreshInstance FAILED for JSFrameworkInit FAILED, intance will invoke instance.onRenderError"
+          );
+        }
+        String err = "[WXBridgeManager] invokeRefreshInstance: framework.js uninitialized.";
+        WXLogUtils.e(err);
+        return;
+      }
+      long start = System.currentTimeMillis();
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d("refreshInstance >>>> instanceId:" + instanceId
+                + ", data:" + refreshData.data + ", isDirty:" + refreshData.isDirty);
+      }
+
+      if (refreshData.isDirty) {
+        return;
+      }
+      WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
+              instanceId);
+      WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
+              refreshData.data == null ? "{}" : refreshData.data);
+      WXJSObject[] args = {instanceIdObj, dataObj};
+      mWXBridge.refreshInstance(instanceId, null, METHOD_REFRESH_INSTANCE, args);
+    } catch (Throwable e) {
+      String err = "[WXBridgeManager] invokeRefreshInstance " + WXLogUtils.getStackTrace(e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "invokeRefreshInstance",
+              err, null);
+      WXLogUtils.e(err);
+    }
+  }
+
+  public void commitJscCrashAlarmMonitor(final String type, final WXErrorCode errorCode, String errMsg,
+                                         String instanceId, String url,Map<String, String> extInfo) {
+    if (TextUtils.isEmpty(type) || errorCode == null) {
+      return;
+    }
+
+    Log.d("ReportCrash", " commitJscCrashAlarmMonitor errMsg " + errMsg);
+    String method = "callReportCrash";
+    String exception = "weex core process crash and restart exception";
+    Map<String, String> extParams = new HashMap<String, String>();
+    extParams.put("jscCrashStack", errMsg);
+    if (null != extInfo){
+      extParams.putAll(extInfo);
+    }
+    IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
+    if (adapter != null) {
+      WXJSExceptionInfo jsException = new WXJSExceptionInfo(instanceId, url, errorCode, method, exception, extParams);
+      adapter.onJSException(jsException);
+      // if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.e(jsException.toString());
+      // }
+    }
+  }
+
+  private boolean isSkipFrameworkInit(String instanceId) {
+    final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    return isSkipFrameworkInit(instance);
+  }
+
+  private boolean isSkipFrameworkInit(WXSDKInstance instance) {
+    if (instance == null) {
+      return false;
+    }
+    return instance.skipFrameworkInit();
+  }
+
+  /**
+   * Create instance.
+   */
+  public void createInstance(final String instanceId, final String template,
+                             final Map<String, Object> options, final String data) {
+    createInstance(instanceId, new Script(template), options, data);
+  }
+
+  public void setLogLevel(final int level, final boolean isPerf) {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        if(mWXBridge != null) {
+          mWXBridge.setLogType(level, isPerf);
+        }
+      }
+    });
+  }
+
+  public void createInstance(final String instanceId, final Script template,
+                             final Map<String, Object> options, final String data) {
+    final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance == null) {
+      WXLogUtils.e("WXBridgeManager", "createInstance failed, SDKInstance does not exist");
+      return;
+    }
+    if (TextUtils.isEmpty(instanceId) || template == null || template.isEmpty() || mJSHandler == null) {
+      instance.onRenderError(
+              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() +
+                      " instanceId==" + instanceId + " template ==" + template + " mJSHandler== " + mJSHandler.toString()
+      );
+
+      instance.getApmForInstance().onStage("createInstance failed return; "+TextUtils.isEmpty(instanceId)+ ","+template.isEmpty()+","+(mJSHandler ==null));
+      return;
+    }
+
+    if (!isSkipFrameworkInit(instanceId) && !isJSFrameworkInit() && reInitCount == 1 && !WXEnvironment.sDebugServerConnectable) {
+      instance.onRenderError(
+              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+              WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() +
+                      " isJSFrameworkInit==" + isJSFrameworkInit() + " reInitCount == 1" );
+      instance.getApmForInstance().onStage("createInstance failed jsfm isn't init return;");
+      post(new Runnable() {
+        @Override
+        public void run() {
+          initFramework("");
+        }
+      }, instanceId, instance,"initFrameworkInCreateInstance");
+      return;
+    }
+
+    WXModuleManager.createDomModule(instance);
+    instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_START);
+    post(new Runnable() {
+      @Override
+      public void run() {
+        instance.getApmForInstance().onStage("wxLoadBundleStartOnJsThread");
+        long start = System.currentTimeMillis();
+        mWXBridge.setPageArgument(instanceId, "renderTimeOrigin", String.valueOf(instance.getWXPerformance().renderTimeOrigin));
+        mWXBridge.setInstanceRenderType(instance.getInstanceId(), instance.getRenderType());
+        invokeCreateInstance(instance, template, options, data);
+        long end = System.currentTimeMillis();
+        instance.getWXPerformance().callCreateInstanceTime = end - start;
+        instance.getWXPerformance().communicateTime =  instance.getWXPerformance().callCreateInstanceTime;
+      }
+    }, instanceId, instance,"createInstance");
+  }
+
+  private void invokeCreateInstance(@NonNull WXSDKInstance instance, Script template,
+                                    Map<String, Object> options, String data) {
+    // add for sandbox, will delete on sandbox ok
+    if (!isSkipFrameworkInit(instance)){
+      initFramework("");
+    }
+
+    if (mMock) {
+      mock(instance.getInstanceId());
+    } else {
+      if (!isSkipFrameworkInit(instance) && !isJSFrameworkInit()) {
+        String err = "[WXBridgeManager] invokeCreateInstance: framework.js uninitialized.";
+        instance.onRenderError(
+                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg()
+        );
+        WXLogUtils.e(err);
+        instance.getApmForInstance().onStage("framework.js uninitialized and return");
+        return;
+      }
+
+      WXModuleManager.registerWhenCreateInstance();
+
+      try {
+        BundType type = BundType.Others;
+        try {
+          long start = System.currentTimeMillis();
+          type = getBundleType(instance.getBundleUrl(), template.getContent());
+
+          if (WXEnvironment.isOpenDebugLog()) {
+            long end = System.currentTimeMillis();
+            WXLogUtils.e("end getBundleType type:" + type.toString() + " time:" + (end - start));
+          }
+        } catch (Throwable e) {
+          WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+
+        try {
+          if (options == null) {
+            options = new HashMap<>();
+          }
+          // on file there is { "framework": "Vue" } or others
+          if (options.get(BUNDLE_TYPE) == null) {
+            // may vue or Rax
+            if (type == BundType.Vue) {
+              options.put(BUNDLE_TYPE, "Vue");
+            } else if (type == BundType.Rax) {
+              options.put(BUNDLE_TYPE, "Rax");
+            } else {
+              options.put(BUNDLE_TYPE, "Others");
+            }
+            Object recordBundleType = options.get(BUNDLE_TYPE);
+            if (recordBundleType instanceof String && "Others".equalsIgnoreCase((String)recordBundleType)){
+              //same as iOS record
+              recordBundleType = "other";
+            }
+            if (null != recordBundleType){
+              instance.getApmForInstance().addProperty(WXInstanceApm.KEY_PAGE_PROPERTIES_BUNDLE_TYPE, recordBundleType);
+            }
+          }
+          if (options.get("env") == null) {
+            options.put("env", mInitParams.toMap());
+          }
+        } catch (Throwable e) {
+          WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+        instance.bundleType = type;
+        if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+          WXLogUtils.d("createInstance >>>> instanceId:" + instance.getInstanceId()
+                  + ", options:"
+                  + WXJsonUtils.fromObjectToJSONString(options)
+                  + ", data:" + data);
+        }
+        WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
+                instance.getInstanceId());
+        WXJSObject instanceObj = new WXJSObject(WXJSObject.String,
+                template.getContent());
+
+        Object extraOption = null;
+        if(options != null && options.containsKey("extraOption")) {
+           extraOption = options.get("extraOption");
+           options.remove("extraOption");
+        }
+
+        WXJSObject extraOptionObj = new WXJSObject(WXJSObject.JSON,
+                extraOption == null ? "{}"
+                        : WXJsonUtils.fromObjectToJSONString(extraOption));
+
+
+        WXJSObject optionsObj = new WXJSObject(WXJSObject.JSON,
+                options == null ? "{}"
+                        : WXJsonUtils.fromObjectToJSONString(options));
+        optionsObj = optionObjConvert(isSandBoxContext, type, optionsObj);
+        WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
+                data == null ? "{}" : data);
+
+        WXJSObject apiObj;
+        if (type == BundType.Rax || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER) {
+          if (mRaxApi == null) {
+            IWXJsFileLoaderAdapter iwxJsFileLoaderAdapter = WXSDKEngine.getIWXJsFileLoaderAdapter();
+            if(iwxJsFileLoaderAdapter != null) {
+              mRaxApi = iwxJsFileLoaderAdapter.loadRaxApi();
+            }
+
+            if(TextUtils.isEmpty(mRaxApi)) {
+              mRaxApi =  WXFileUtils.loadAsset("weex-rax-api.js", WXEnvironment.getApplication());
+            }
+          }
+          apiObj = new WXJSObject(WXJSObject.String,
+                  mRaxApi);
+        } else {
+          apiObj = new WXJSObject(WXJSObject.String,
+                  "");
+        }
+
+        // When render strategy is data_render, put it into options. Others keep null.
+        WXJSObject renderStrategy = null;
+        if (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER) {
+          renderStrategy = new WXJSObject(WXJSObject.String, WXRenderStrategy.DATA_RENDER.getFlag());
+        } else if (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY) {
+          renderStrategy = new WXJSObject(WXJSObject.String, WXRenderStrategy.DATA_RENDER_BINARY.getFlag());
+          // In DATA_RENDER_BINARY strategy script is binary
+          instanceObj.data = template.getBinary();
+        }else if (instance.getRenderStrategy() == WXRenderStrategy.JSON_RENDER) {
+             renderStrategy = new WXJSObject(WXJSObject.String, WXRenderStrategy.JSON_RENDER.getFlag());
+        }
+
+        WXJSObject[] args = {instanceIdObj, instanceObj, optionsObj,
+                dataObj, apiObj, renderStrategy, extraOptionObj};
+
+        instance.setTemplate(template.getContent());
+
+        instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
+
+        // if { "framework": "Vue" } or  { "framework": "Rax" } will use invokeCreateInstanceContext
+        // others will use invokeExecJS
+        if (!isSandBoxContext) {
+          instance.getApmForInstance().onStage("!isSandBoxContext,and excute");
+          WXLogUtils.e("Instance " + instance.getInstanceId() + " Did Not Render in SandBox Mode");
+          invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
+          return;
+        }
+        if (type == BundType.Vue || type == BundType.Rax
+                || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER
+                || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY
+                || instance.getRenderStrategy() == WXRenderStrategy.JSON_RENDER) {
+          instance.getApmForInstance().onStage("wxBeforeInvokeCreateInstanceContext");
+
+          WXLogUtils.d("Instance " + instance.getInstanceId() + " Render in SandBox Mode And Render Type is "
+                  + type + " Render Strategy is " + instance.getRenderStrategy());
+
+          int ret = invokeCreateInstanceContext(instance.getInstanceId(), null, "createInstanceContext", args, false);
+          instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
+          if(ret == 0) {
+            String err = "[WXBridgeManager] invokeCreateInstance : " + instance.getTemplateInfo();
+            WXLogUtils.e("Instance " + instance.getInstanceId() + "Render error : " + err);
+            instance.onRenderError(
+                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() + err);
+          }
+          return;
+        } else {
+          //bad case for js bundle with out bundletype header //vue or rax
+          //WXExceptionUtils.commitCriticalExceptionRT(
+          //      instance.getInstanceId(),
+          //      WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE,
+          //      "invokeCreateInstance",
+          //      WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE.getErrorMsg(),
+          //      null
+          //);
+
+          WXLogUtils.d("Instance " + instance.getInstanceId() + "Did not Render in SandBox Mode And Render Type is "
+                + type + " Render Strategy is " + instance.getRenderStrategy());
+          instance.getApmForInstance().onStage("StartInvokeExecJSBadBundleType");
+          invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
+          instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
+          return;
+        }
+      } catch (Throwable e) {
+        String err = "[WXBridgeManager] invokeCreateInstance " + e.getCause()
+                + instance.getTemplateInfo();
+        instance.getApmForInstance().onStage("createInstance error :"+e.toString());
+        WXLogUtils.e("Instance " + instance.getInstanceId() + "Render error : " + err);
+        instance.onRenderError(
+                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() + err);
+        WXLogUtils.e(err);
+      }
+    }
+  }
+
+  public WXJSObject optionObjConvert(boolean useSandBox, BundType type, WXJSObject opt) {
+    if (!useSandBox) {
+      return opt;
+    }
+    try {
+      String data = opt.data.toString();
+      JSONObject obj = JSON.parseObject(data);
+      JSONObject optEnv;
+      if ((optEnv = obj.getJSONObject("env")) != null) {
+        JSONObject opts = optEnv.getJSONObject("options");
+        if (opts != null) {
+          for (String s : opts.keySet()) {
+            optEnv.put(s, opts.getString(s));
+          }
+        }
+      }
+      return new WXJSObject(WXJSObject.JSON, obj.toString());
+    } catch (Throwable e) {
+      WXLogUtils.e(WXLogUtils.getStackTrace(e));
+    }
+    return opt;
+
+  }
+
+  /**
+   * check bundleType
+   * @param url
+   * @param temp
+   * @return
+   */
+  public BundType getBundleType(String url, String temp) {
+    try {
+      if (url != null) {
+        Uri uri = Uri.parse(url);
+        String type = uri.getQueryParameter(BUNDLE_TYPE);
+        if ("Vue".equals(type) || "vue".equals(type)) {
+          return BundType.Vue;
+        } else if ("Rax".equals(type) || "rax".equals(type)) {
+          return BundType.Rax;
+        }
+      }
+      if (temp != null) {
+        final String FRAMEWORK="framework", VUE="vue", RAX="rax";
+
+        // Find the first line that starts with '//' and convert it to json
+        int bundleTypeStart = temp.indexOf("//");
+        int bundleTypeEnd = temp.indexOf("\n", bundleTypeStart);
+        JSONObject bundleType = JSONObject.parseObject(
+            temp.substring(bundleTypeStart+2, bundleTypeEnd));
+        String type = bundleType.getString(FRAMEWORK);
+        if(VUE.equalsIgnoreCase(type)){
+          return BundType.Vue;
+        }
+        else if(RAX.equalsIgnoreCase(type)){
+          return BundType.Rax;
+        }
+        else{
+          // '//{ "framework": "Vue"}' is not found.
+          String regEx = "(use)(\\s+)(weex:vue)";
+          Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
+          if (pattern.matcher(temp).find()) {
+            return BundType.Vue;
+          }
+          regEx = "(use)(\\s+)(weex:rax)";
+          pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
+          if (pattern.matcher(temp).find()) {
+            return BundType.Rax;
+          }
+        }
+      }
+      return BundType.Others;
+    } catch (Throwable e) {
+      WXLogUtils.e(WXLogUtils.getStackTrace(e));
+      return BundType.Others;
+    }
+  }
+
+  private void mock(String instanceId) {
+
+  }
+
+  public void destroyInstance(final String instanceId) {
+    if (mJSHandler == null
+            || TextUtils.isEmpty(instanceId)) {
+      return;
+    }
+    if (mDestroyedInstanceId != null) {
+      mDestroyedInstanceId.add(instanceId);
+    }
+    // clear message with instanceId
+    mJSHandler.removeCallbacksAndMessages(instanceId);
+    post(new Runnable() {
+      @Override
+      public void run() {
+        removeTaskByInstance(instanceId);
+        invokeDestroyInstance(instanceId);
+      }
+    }, instanceId, null, "destroyInstance");
+  }
+
+  private void removeTaskByInstance(String instanceId) {
+    mNextTickTasks.removeFromMapAndStack(instanceId);
+  }
+
+  private void invokeDestroyInstance(String instanceId) {
+    try {
+      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+        WXLogUtils.d("destroyInstance >>>> instanceId:" + instanceId);
+      }
+      WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
+              instanceId);
+      WXJSObject[] args = {instanceIdObj};
+      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+        invokeDestoryInstance(instanceId, null, METHOD_DESTROY_INSTANCE, args, true);
+        // invokeExecJS(instanceId, null, METHOD_DESTROY_INSTANCE, args);
+      }
+    } catch (Throwable e) {
+      String err = "[WXBridgeManager] invokeDestroyInstance " + e.getCause();
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "invokeDestroyInstance", err, null);
+      WXLogUtils.e(err);
+    }
+  }
+
+  @Override
+  public boolean handleMessage(Message msg) {
+    if (msg == null) {
+      return false;
+    }
+
+    int what = msg.what;
+    switch (what) {
+      case WXJSBridgeMsgType.INIT_FRAMEWORK:
+        invokeInitFramework(msg);
+        break;
+      case WXJSBridgeMsgType.CALL_JS_BATCH:
+        invokeCallJSBatch(msg);
+        break;
+      case WXJSBridgeMsgType.SET_TIMEOUT:
+        TimerInfo timerInfo = (TimerInfo) msg.obj;
+        if (timerInfo == null) {
+          break;
+        }
+        WXJSObject obj = new WXJSObject(WXJSObject.String, timerInfo.callbackId);
+        WXJSObject[] args = {obj};
+        invokeExecJS("", null, METHOD_SET_TIMEOUT, args);
+        break;
+      case WXJSBridgeMsgType.TAKE_HEAP_SNAPSHOT:
+        if (msg.obj != null) {
+          String filename = (String) msg.obj;
+          mWXBridge.takeHeapSnapshot(filename);
+        }
+        break;
+      default:
+        break;
+    }
+    return false;
+  }
+
+  private void invokeExecJS(String instanceId, String namespace, String function, WXJSObject[] args) {
+    invokeExecJS(instanceId, namespace, function, args, true);
+  }
+
+  public void invokeExecJS(final String instanceId, final String namespace, final String function,
+                           final WXJSObject[] args, boolean logTaskDetail) {
+    if (WXEnvironment.isOpenDebugLog() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
+              .append("function:").append(function);
+      if (logTaskDetail) {
+        mLodBuilder.append(" tasks:").append(argsToJSON(args));
+      }
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+    final long start = System.currentTimeMillis();
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
+      Pair<Pair<String,Object>, Boolean> data = null;
+      if(args.length!=2 || !(args[0].data instanceof String)
+          || !(args[1].data instanceof String)
+          || (data = extractCallbackArgs((String) args[1].data))==null){
+        WXLogUtils.w("invokeExecJS on data render that is not a callback call");
+        return;
+      }
+      callbackJavascriptOnDataRender(instanceId, (String) data.first.first, data.first.second, data.second);
+    } else {
+
+      WXThread.secure(new Runnable() {
+        @Override
+        public void run() {
+          mWXBridge.execJS(instanceId, namespace, function, args);
+        }
+      }, instance, "ExecJs").run();
+    }
+    if (null != instance){
+      long diff = System.currentTimeMillis()-start;
+      instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_NUM,1);
+      instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_TIME,diff);
+      instance.callJsTime(diff);
+    }
+  }
+
+  private Pair<Pair<String,Object>,Boolean> extractCallbackArgs(String data) {
+    try {
+      JSONArray obj = JSON.parseArray(data);
+      JSONObject arg_obj = obj.getJSONObject(0);
+      JSONArray args = arg_obj.getJSONArray("args");
+      if (args.size()!=3){
+        return null;
+      }
+      String method = arg_obj.getString("method");
+      if (!"callback".equals(method)){
+        return null;
+      }
+
+      return new Pair<Pair<String,Object>, Boolean>(new Pair<String, Object>(args.getString(0), args.getJSONObject(1)),args.getBooleanValue(2));
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
+  public int invokeCreateInstanceContext(String instanceId, String namespace, String function,
+                                          WXJSObject[] args, boolean logTaskDetail) {
+    WXLogUtils.d("invokeCreateInstanceContext instanceId:" + instanceId + " function:"
+            + function + String.format(" isJSFrameworkInit:%b", isJSFrameworkInit()));
+    mLodBuilder.append("createInstanceContext >>>> instanceId:").append(instanceId)
+            .append("function:").append(function);
+    if (logTaskDetail)
+      mLodBuilder.append(" tasks:").append(WXJsonUtils.fromObjectToJSONString(args));
+    WXLogUtils.d(mLodBuilder.substring(0));
+    mLodBuilder.setLength(0);
+    // }
+    return mWXBridge.createInstanceContext(instanceId, namespace, function, args);
+  }
+
+  public void invokeDestoryInstance(String instanceId, String namespace, String function,
+                                    WXJSObject[] args, boolean logTaskDetail) {
+    // if (WXEnvironment.isApkDebugable()) {
+    mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
+            .append("function:").append(function);
+    if (logTaskDetail)
+      mLodBuilder.append(" tasks:").append(WXJsonUtils.fromObjectToJSONString(args));
+    WXLogUtils.d(mLodBuilder.substring(0));
+    mLodBuilder.setLength(0);
+    // }
+    mWXBridge.removeInstanceRenderType(instanceId);
+    mWXBridge.destoryInstance(instanceId, namespace, function, args);
+  }
+
+  private void execJSOnInstance(final EventResult eventCallback, final String instanceId, final String js, final int type) {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        String ret = invokeExecJSOnInstance(instanceId, js, type);
+        eventCallback.onCallback(ret);
+      }
+    });
+  }
+
+  private String invokeExecJSOnInstance(String instanceId, String js, int type) {
+    // if (WXEnvironment.isApkDebugable()) {
+    mLodBuilder.append("execJSOnInstance >>>> instanceId:").append(instanceId);
+    WXLogUtils.d(mLodBuilder.substring(0));
+    mLodBuilder.setLength(0);
+    // }
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      return mWXBridge.execJSOnInstance(instanceId, js, type);
+    }
+    return null;
+  }
+
+  private void invokeExecJSWithCallback(String instanceId, String namespace, String function,
+                                        WXJSObject[] args , ResultCallback callback, boolean logTaskDetail){
+    if (WXEnvironment.isOpenDebugLog() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
+              .append("function:").append(function);
+      if(logTaskDetail) {
+        mLodBuilder.append(" tasks:").append(argsToJSON(args));
+      }
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.execJSWithCallback(instanceId, namespace, function, args, callback);
+    }
+  }
+
+  public @NonNull static String argsToJSON(WXJSObject[] args) {
+    StringBuilder builder = new StringBuilder();
+    builder.append("[");
+    for(WXJSObject object : args){
+      builder.append(WXWsonJSONSwitch.fromObjectToJSONString(object));
+      builder.append(",");
+    }
+    builder.append("]");
+    return  builder.toString();
+  }
+
+  private void invokeInitFramework(Message msg) {
+    String framework = "";
+    if (msg.obj != null) {
+      framework = (String) msg.obj;
+    }
+
+    if (WXUtils.getAvailMemory(WXEnvironment.getApplication()) > LOW_MEM_VALUE) {
+      initFramework(framework);
+    }
+  }
+
+  public static long sInitFrameWorkTimeOrigin;
+  public static StringBuilder sInitFrameWorkMsg = new StringBuilder();
+
+  private void initFramework(String framework) {
+    LogDetail logDetail = new LogDetail();
+    logDetail.name("initFramework");
+    logDetail.taskStart();
+    if (WXSDKEngine.isSoInitialized() && !isJSFrameworkInit()) {
+      sInitFrameWorkTimeOrigin = System.currentTimeMillis();
+      if (TextUtils.isEmpty(framework)) {
+        // if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d("weex JS framework from assets");
+        // }
+
+        LogDetail logDetail2 = new LogDetail();
+        logDetail2.name("loadJSFramework");
+        logDetail2.taskStart();
+
+        IWXJsFileLoaderAdapter wxJsFileLoaderAdapter = WXSDKEngine.getIWXJsFileLoaderAdapter();
+
+        if (!isSandBoxContext) {
+          if(wxJsFileLoaderAdapter != null) {
+            framework = wxJsFileLoaderAdapter.loadJsFramework();
+          }
+
+          if(TextUtils.isEmpty(framework)) {
+            framework = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
+          }
+        } else {
+          if(wxJsFileLoaderAdapter != null) {
+            framework = wxJsFileLoaderAdapter.loadJsFrameworkForSandBox();
+          }
+
+          if(TextUtils.isEmpty(framework)) {
+            framework = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
+          }
+        }
+        sInitFrameWorkMsg.append("| weex JS framework from assets, isSandBoxContext: ").append(isSandBoxContext);
+        logDetail2.taskEnd();
+      }
+      if (TextUtils.isEmpty(framework)) {
+        setJSFrameworkInit(false);
+        sInitFrameWorkMsg.append("| framework isEmpty ");
+        WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK,
+                "initFramework", "framework is empty!! ", null);
+        return;
+      }
+      try {
+        if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
+          long start = System.currentTimeMillis();
+          WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkStart();
+          WXEnvironment.sJSFMStartListenerTime = System.currentTimeMillis() - start;
+          try {
+            IWXUserTrackAdapter adapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
+            if (null != adapter){
+              Map<String,Serializable> params = new HashMap<>(1);
+              params.put("time",String.valueOf(WXEnvironment.sJSFMStartListenerTime));
+              adapter.commit(WXEnvironment.getApplication(),"sJSFMStartListener",IWXUserTrackAdapter.COUNTER,null,params);
+            }
+          }catch (Exception e){
+            WXLogUtils.e(WXLogUtils.getStackTrace(e));
+          }
+        }
+
+        long start = System.currentTimeMillis();
+        String crashFile = "";
+        try {
+          crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
+        } catch (Exception e) {
+          WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+        boolean pieSupport = true;
+        try {
+          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+            pieSupport = false;
+          }
+        } catch (Exception e) {
+          WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+        sInitFrameWorkMsg.append(" | pieSupport:").append(pieSupport);
+        WXLogUtils.d("[WXBridgeManager] initFrameworkEnv crashFile:" + crashFile + " pieSupport:" + pieSupport);
+        // extends initFramework
+        LogDetail logDetail3 = new LogDetail();
+        logDetail3.name("native initFrameworkEnv");
+        logDetail3.taskStart();
+        if (mWXBridge.initFrameworkEnv(framework, assembleDefaultOptions(), crashFile, pieSupport) == INIT_FRAMEWORK_OK) {
+          logDetail3.taskEnd();
+          WXEnvironment.sJSLibInitTime = System.currentTimeMillis() - start;
+          WXEnvironment.sSDKInitTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart;
+          setJSFrameworkInit(true);
+          logDetail.taskEnd();
+          if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
+            WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkReady();
+          }
+
+          execRegisterFailTask();
+          WXEnvironment.JsFrameworkInit = true;
+          sInitFrameWorkCount++;
+          WXLogUtils.e("initFrameWorkCount :"+ sInitFrameWorkCount);
+          registerDomModule();
+          trackComponentAndModulesTime();
+        } else {
+          sInitFrameWorkMsg.append(" | ExecuteJavaScript fail, reInitCount").append(reInitCount);
+          if (reInitCount > 1) {
+            WXLogUtils.e("[WXBridgeManager] invokeReInitFramework  ExecuteJavaScript fail");
+          } else {
+            WXLogUtils.e("[WXBridgeManager] invokeInitFramework  ExecuteJavaScript fail");
+          }
+        }
+      } catch (Throwable e) {
+        sInitFrameWorkMsg.append(" | invokeInitFramework exception ").append(e.toString());
+        if (reInitCount > 1) {
+          WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
+        } else {
+          WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
+        }
+      }
+
+    }
+  }
+
+  private void trackComponentAndModulesTime() {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        WXEnvironment.sComponentsAndModulesReadyTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart;
+      }
+    });
+  }
+
+  @SuppressWarnings("unchecked")
+  private void invokeCallJSBatch(Message message) {
+    if (mNextTickTasks.isEmpty() || !isJSFrameworkInit()) {
+      if (!isJSFrameworkInit()) {
+        WXLogUtils.e("[WXBridgeManager] invokeCallJSBatch: framework.js uninitialized!!  message:" + message.toString());
+      }
+      return;
+    }
+
+    try {
+      Object instanceId = message.obj;
+
+      Object task = null;
+      Stack<String> instanceStack = mNextTickTasks.getInstanceStack();
+      int size = instanceStack.size();
+      for (int i = size - 1; i >= 0; i--) {
+        instanceId = instanceStack.get(i);
+        task = mNextTickTasks.remove(instanceId);
+        if (task != null && !((ArrayList) task).isEmpty()) {
+          break;
+        }
+      }
+      if (null != task){
+        task = ((ArrayList) task).toArray();
+
+        WXJSObject[] args = {
+            new WXJSObject(WXJSObject.String, instanceId),
+            WXWsonJSONSwitch.toWsonOrJsonWXJSObject(task)};
+
+        invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, args);
+      }
+    } catch (Throwable e) {
+      WXLogUtils.e("WXBridgeManager", e);
+      String err = "invokeCallJSBatch#" + WXLogUtils.getStackTrace(e);
+      WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK,
+              "invokeCallJSBatch", err, null);
+    }
+
+    // If task is not empty, loop until it is empty
+    if (!mNextTickTasks.isEmpty()) {
+      mJSHandler.sendEmptyMessage(WXJSBridgeMsgType.CALL_JS_BATCH);
+    }
+  }
+
+  private WXParams assembleDefaultOptions() {
+    checkJsEngineMultiThread();
+
+    Map<String, String> config = WXEnvironment.getConfig();
+    WXParams wxParams = new WXParams();
+    wxParams.setPlatform(config.get(WXConfig.os));
+    wxParams.setCacheDir(config.get(WXConfig.cacheDir));
+    wxParams.setOsVersion(config.get(WXConfig.sysVersion));
+    wxParams.setAppVersion(config.get(WXConfig.appVersion));
+    wxParams.setWeexVersion(config.get(WXConfig.weexVersion));
+    wxParams.setDeviceModel(config.get(WXConfig.sysModel));
+    wxParams.setShouldInfoCollect(config.get("infoCollect"));
+    wxParams.setLogLevel(config.get(WXConfig.logLevel));
+    wxParams.setLayoutDirection(config.get(WXConfig.layoutDirection));
+    wxParams.setUseSingleProcess(isUseSingleProcess ? "true" : "false");
+    wxParams.setCrashFilePath(WXEnvironment.getCrashFilePath(WXEnvironment.getApplication().getApplicationContext()));
+    wxParams.setLibJsbPath(WXEnvironment.CORE_JSB_SO_PATH);
+    wxParams.setLibJssPath(WXEnvironment.getLibJssRealPath());
+    wxParams.setLibIcuPath(WXEnvironment.getLibJssIcuPath());
+    wxParams.setLibLdPath(WXEnvironment.getLibLdPath());
+    String libJScRealPath = WXEnvironment.getLibJScRealPath();
+    wxParams.setLibJscPath(TextUtils.isEmpty(libJScRealPath)? "" : new File(libJScRealPath).getParent());
+    String appName = config.get(WXConfig.appName);
+    if (!TextUtils.isEmpty(appName)) {
+      wxParams.setAppName(appName);
+    }
+    wxParams.setDeviceWidth(TextUtils.isEmpty(config.get("deviceWidth")) ? String.valueOf(WXViewUtils.getScreenWidth(WXEnvironment.sApplication)) : config.get("deviceWidth"));
+    wxParams.setDeviceHeight(TextUtils.isEmpty(config.get("deviceHeight")) ? String.valueOf(WXViewUtils.getScreenHeight(WXEnvironment.sApplication)) : config.get("deviceHeight"));
+    Map<String, String> customOptions = WXEnvironment.getCustomOptions();
+    customOptions.put("enableBackupThread", String.valueOf(jsEngineMultiThreadEnable()));
+    IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
+    if(wxJscProcessManager != null) {
+      customOptions.put("enableBackupThreadCache", String.valueOf(wxJscProcessManager.enableBackUpThreadCache()));
+    }
+
+    if (!WXEnvironment.sUseRunTimeApi){
+      customOptions.put("__enable_native_promise__","true");
+    }
+
+    String enableAlarmSignal = "true";
+    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+    if (null != adapter){
+      try {
+        if (adapter.checkMode("white_screen_fix_open")){
+          WXEnvironment.isWsFixMode = true;
+          enableAlarmSignal = "true";
+        }else {
+          enableAlarmSignal = adapter.getConfigWhenInit("wxapm","enableAlarmSignal",enableAlarmSignal);
+          WXEnvironment.isWsFixMode = "true".equalsIgnoreCase(enableAlarmSignal);
+        }
+      }catch (Exception e){
+        e.printStackTrace();
+      }
+    }
+    if (null != enableAlarmSignal){
+      customOptions.put("enableAlarmSignal",enableAlarmSignal);
+    }
+    WXLogUtils.e("weex","enableAlarmSignal:"+enableAlarmSignal);
+
+    wxParams.setOptions(customOptions);
+    wxParams.setNeedInitV8(WXSDKManager.getInstance().needInitV8());
+    mInitParams = wxParams;
+    return wxParams;
+  }
+
+  public WXParams getInitParams() {
+    return mInitParams;
+  }
+
+  private void execRegisterFailTask() {
+
+    if (mRegisterModuleFailList.size() > 0) {
+      List<Map<String, Object>> moduleReceiver = new ArrayList<>();
+      for (int i = 0, moduleCount = mRegisterModuleFailList.size(); i < moduleCount; ++i) {
+        invokeRegisterModules(mRegisterModuleFailList.get(i), moduleReceiver);
+      }
+      mRegisterModuleFailList.clear();
+      if (moduleReceiver.size() > 0) {
+        mRegisterModuleFailList.addAll(moduleReceiver);
+      }
+    }
+
+    if (mRegisterComponentFailList.size() > 0) {
+      List<Map<String, Object>> receiver = new ArrayList<>();
+      invokeRegisterComponents(mRegisterComponentFailList, receiver);
+      mRegisterComponentFailList.clear();
+      if (receiver.size() > 0) {
+        mRegisterComponentFailList.addAll(receiver);
+      }
+    }
+
+    if (mRegisterServiceFailList.size() > 0) {
+      List<String> receiver = new ArrayList<>();
+      for (String service : mRegisterServiceFailList) {
+        invokeExecJSService(service, receiver);
+      }
+      mRegisterServiceFailList.clear();
+      if (receiver.size() > 0) {
+        mRegisterServiceFailList.addAll(receiver);
+      }
+    }
+  }
+
+  /**
+   * Register Android module
+   *
+   * @param modules the format is like
+   *                {'dom':['updateAttrs','updateStyle'],'event':['openUrl']}
+   */
+
+  public void registerModules(final Map<String, Object> modules) {
+    if (modules != null && modules.size() != 0) {
+      if (isJSThread()) {
+        invokeRegisterModules(modules, mRegisterModuleFailList);
+      } else {
+        post(new Runnable() {
+          @Override
+          public void run() {
+            invokeRegisterModules(modules, mRegisterModuleFailList);
+          }
+        });
+      }
+    }
+  }
+
+  /**
+   * Registered component
+   */
+  public void registerComponents(final List<Map<String, Object>> components) {
+    if (mJSHandler == null || components == null
+            || components.size() == 0) {
+      return;
+    }
+    Runnable runnable = new Runnable() {
+      @Override
+      public void run() {
+        invokeRegisterComponents(components, mRegisterComponentFailList);
+      }
+    };
+
+    if(isJSThread() && isJSFrameworkInit()){
+      runnable.run();
+    }else{
+      post(runnable);
+    }
+  }
+
+  public void execJSService(final String service) {
+    postWithName(new Runnable() {
+      @Override
+      public void run() {
+        invokeExecJSService(service, mRegisterServiceFailList);
+      }
+    },null,"execJSService");
+  }
+
+  private void invokeExecJSService(String service, List<String> receiver) {
+    try {
+      if (!isJSFrameworkInit()) {
+        WXLogUtils.e("[WXBridgeManager] invoke execJSService: framework.js uninitialized.");
+        receiver.add(service);
+        return;
+      }
+      mWXBridge.execJSService(service);
+    } catch (Throwable e) {
+      WXLogUtils.e("[WXBridgeManager] invokeRegisterService:", e);
+
+      Map<String, String> data = new HashMap<String, String>();
+      data.put("inputParams",service + "||" + receiver.toString());
+
+      WXExceptionUtils.commitCriticalExceptionRT("invokeExecJSService",
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE,
+              "invokeExecJSService",
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE.getErrorMsg()
+                      + "[WXBridgeManager] invokeRegisterService:"
+                      + WXLogUtils.getStackTrace(e),
+              data);
+    }
+  }
+
+  public boolean isJSThread() {
+    return mJSThread != null && mJSThread.getId() == Thread.currentThread().getId();
+  }
+
+  private void invokeRegisterModules(Map<String, Object> modules, List<Map<String, Object>> failReceiver) {
+    if (modules == null || !isJSFrameworkInit()) {
+      if (!isJSFrameworkInit()) {
+        WXLogUtils.d("[WXinvokeRegisterModulesBridgeManager] invokeRegisterModules: framework.js uninitialized.");
+      }
+      failReceiver.add(modules);
+      return;
+    }
+
+    WXJSObject[] args = {WXWsonJSONSwitch.toWsonOrJsonWXJSObject(modules)};
+    String errorMsg = null;
+    try{
+      // TODO use a better way
+      if (mWXBridge instanceof WXBridge) {
+        ((WXBridge) mWXBridge).registerModuleOnDataRenderNode(WXJsonUtils.fromObjectToJSONString(modules));
+      }
+    } catch (Throwable e){
+      WXLogUtils.e("Weex [data_render register err]", e);
+    }
+    try {
+        if(0 == mWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args)) {
+            errorMsg = "execJS error";
+        }
+      try {
+        Iterator<String> iter = modules.keySet().iterator();
+        while (iter.hasNext()) {
+          String module = iter.next();
+          if (module != null) {
+            WXModuleManager.resetModuleState(module, true);
+            //WXLogUtils.e("[WXBridgeManager]invokeRegisterModules METHOD_REGISTER_MODULES success module:" + module);
+          }
+        }
+      } catch (Throwable e) {
+        WXLogUtils.e("Weex [invokeRegisterModules]", e);
+      }
+    } catch (Throwable e) {
+      errorMsg = WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() +
+                " \n " + e.getMessage() + modules.entrySet().toString();
+    }
+
+    if(!TextUtils.isEmpty(errorMsg)) {
+        WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", errorMsg);
+        WXExceptionUtils.commitCriticalExceptionRT(null,
+                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES,
+                "invokeRegisterModules", errorMsg,
+                null );
+    }
+  }
+
+  private void invokeRegisterComponents(List<Map<String, Object>> components, List<Map<String, Object>> failReceiver) {
+    if (components == failReceiver) {
+      throw new RuntimeException("Fail receiver should not use source.");
+    }
+    if (!isJSFrameworkInit()) {
+      //WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents: framework.js uninitialized.");
+
+      for (Map<String, Object> comp : components) {
+        failReceiver.add(comp);
+      }
+      return;
+    }
+    if (components == null) {
+      return;
+    }
+
+    try{
+      // TODO use a better way
+      if (mWXBridge instanceof WXBridge) {
+        ((WXBridge) mWXBridge).registerComponentOnDataRenderNode(WXJsonUtils.fromObjectToJSONString(components));
+      }
+    } catch (Throwable e){
+      WXLogUtils.e("Weex [data_render register err]", e);
+    }
+
+    WXJSObject[] args = {WXWsonJSONSwitch.toWsonOrJsonWXJSObject(components)};
+    String errorMsg = null;
+    try {
+      if(0 == mWXBridge.execJS("", null, METHOD_REGISTER_COMPONENTS, args)) {
+          errorMsg = "execJS error";
+      }
+    } catch (Throwable e) {
+        errorMsg = WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT
+                + args.toString()
+                + WXLogUtils.getStackTrace(e);
+    }
+
+    if(!TextUtils.isEmpty(errorMsg)) {
+        WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents ", errorMsg);
+        WXExceptionUtils.commitCriticalExceptionRT(null,
+                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT,
+                METHOD_REGISTER_COMPONENTS, errorMsg,
+                null);
+    }
+  }
+
+  public void destroy() {
+    if (mJSThread != null) {
+      mJSThread.quit();
+    }
+    mBridgeManager = null;
+    if (mDestroyedInstanceId != null) {
+      mDestroyedInstanceId.clear();
+    }
+
+  }
+
+  /**
+   * Report JavaScript Exception
+   */
+  public void reportJSException(String instanceId, String function,
+                                String exception) {
+    WXLogUtils.e("reportJSException >>>> instanceId:" + instanceId
+            + ", exception function:" + function + ", exception:"
+            + exception);
+    WXSDKInstance instance = null;
+    WXErrorCode reportErrorCode = WXErrorCode.WX_ERR_JS_EXECUTE;
+    if (instanceId != null && (instance = WXSDKManager.getInstance().getSDKInstance(instanceId)) != null) {
+      instance.setHasException(true);
+      exception +=   "\n getTemplateInfo==" +instance.getTemplateInfo();//add network header info
+      if ((METHOD_CREATE_INSTANCE.equals(function)) || !instance.isContentMd5Match()) {
+        try {
+          //data render mode should report exception instead of reload page,
+          // so we use !isSkipFrameworkInit(instanceId) to skip the positive branch of if clause.
+          if (!isSkipFrameworkInit(instanceId) && isJSFrameworkInit() && (reInitCount > 1 && reInitCount < 10) && !instance.isNeedReLoad()) {
+            new ActionReloadPage(instanceId, true).executeAction();
+            instance.setNeedLoad(true);
+            return;
+          } else {
+            String errorMsg = new StringBuilder()
+                .append(WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg())
+                .append(", exception function:").append(function)
+                .append(", exception:").append(exception)
+                .append(", extInitTime:").append(System.currentTimeMillis()-WXBridgeManager.sInitFrameWorkTimeOrigin).append("ms")
+                .append(", extInitErrorMsg:").append(WXBridgeManager.sInitFrameWorkMsg.toString())
+                .toString();
+            instance.onRenderError(//DegradPassivity to H5
+                     WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
+                     errorMsg
+            );
+            if (!WXEnvironment.sInAliWeex){
+              WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE, function,exception,null);
+            }
+            return;
+          }
+        } catch (Exception e) {
+          WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+      }
+      if (METHOD_CREATE_INSTANCE.equals(function) && !instance.getApmForInstance().hasAddView){
+        reportErrorCode = WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE;
+      } else if ( METHOD_CREATE_INSTANCE_CONTEXT.equals(function) && !instance.getApmForInstance().hasAddView){
+        reportErrorCode = WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE_CONTEXT;
+      } else if (
+          (METHOD_UPDATE_COMPONENT_WITH_DATA.equals(function) ||
+          METHOD_CREATE_PAGE_WITH_CONTENT.equals(function) ||
+          METHOD_POST_TASK_TO_MSG_LOOP.equals(function) ||
+              METHOD_JSFM_NOT_INIT_IN_EAGLE_MODE.equals(function) )
+          && !instance.getApmForInstance().hasAddView){
+        reportErrorCode = WXErrorCode.WX_DEGRAD_EAGLE_RENDER_ERROR;
+      } else if (METHOD_MOVE_RENDER_OBJECT.equals(function)) {
+        reportErrorCode = WXErrorCode.WX_ERROR_MOVE_RENDER_OBJECT_OUT_OF_BOUNDS;
+      }
+      instance.onJSException(reportErrorCode.getErrorCode(), function, exception);
+    }
+    doReportJSException(instanceId,function,reportErrorCode,exception);
+  }
+
+  private void doReportJSException(String instanceId, String function,WXErrorCode reportCode, String exception){
+    WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+    IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
+    if (adapter != null) {
+      String exceptionId = instanceId;
+
+      if (TextUtils.isEmpty(instanceId)) {
+        exceptionId = "instanceIdisNull";
+      }
+
+      if (instance == null) {
+        if (("initFramework").equals(function)) {
+          String exceptionExt = null;
+          try {
+            if (WXEnvironment.getApplication() != null) {
+              final String fileName = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath() + INITLOGFILE;
+              try {
+                File file = new File(fileName);
+                if (file.exists()) {
+                  if (file.length() > 0) {
+                    StringBuilder result = new StringBuilder();
+                    try {
+                      InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
+                      BufferedReader br = new BufferedReader(read);
+                      String s = null;
+                      while ((s = br.readLine()) != null) {
+                        result.append(s + "\n");
+                      }
+                      exceptionExt = result.toString();
+                      br.close();
+                    } catch (Exception e) {
+                      WXLogUtils.e(WXLogUtils.getStackTrace(e));
+                    }
+                  }
+                  file.delete();
+                }
+              } catch (Throwable throwable) {
+                WXLogUtils.e(WXLogUtils.getStackTrace(throwable));
+              }
+            }
+          } catch (Throwable e) {
+            WXLogUtils.e(WXLogUtils.getStackTrace(e));
+          }
+          exception += "\n" + exceptionExt;
+          WXLogUtils.e("reportJSException:" + exception);
+
+        }
+      }
+
+
+      WXExceptionUtils.commitCriticalExceptionRT(exceptionId, reportCode,
+            function,
+          reportCode.getErrorMsg() + exception,
+            null);
+
+    }
+  }
+
+  private void registerDomModule() throws WXException {
+    /** Tell Javascript Framework what methods you have. This is Required.**/
+    Map<String, Object> domMap = new HashMap<>();
+    domMap.put(WXDomModule.WXDOM, WXDomModule.METHODS);
+    registerModules(domMap);
+  }
+
+  //This method is deprecated because of performance issue.
+  @Deprecated
+  public void notifyTrimMemory() {
+
+  }
+
+  /**
+   * update js server global config, current support turn wson off
+   * by pass wson_off
+   * */
+  public static void  updateGlobalConfig(String config) {
+    if(TextUtils.isEmpty(config)){
+      config = "none";
+    }
+    if(!TextUtils.equals(config, globalConfig)){
+      globalConfig = config;
+      WXEnvironment.addCustomOptions(GLOBAL_CONFIG_KEY, globalConfig);
+      Runnable runnable = new Runnable() {
+        @Override
+        public void run() {
+          if(mBridgeManager != null){
+            if(mBridgeManager.isJSFrameworkInit()){
+              if(mBridgeManager.mWXBridge instanceof WXBridge) {
+                final WXBridge bridge = (WXBridge) mBridgeManager.mWXBridge;
+                bridge.nativeUpdateGlobalConfig(globalConfig);
+              }
+            }
+          }
+          if(globalConfig.contains(WXWsonJSONSwitch.WSON_OFF)){
+            WXWsonJSONSwitch.USE_WSON = false;
+          }else{
+            WXWsonJSONSwitch.USE_WSON = true;
+          }
+        }
+      };
+      if(mBridgeManager != null && mBridgeManager.isJSFrameworkInit()){
+        mBridgeManager.post(runnable);
+      }else{
+        runnable.run();
+      }
+    }
+  }
+
+  public
+  @Nullable
+  Looper getJSLooper() {
+    Looper ret = null;
+    if (mJSThread != null) {
+      ret = mJSThread.getLooper();
+    }
+    return ret;
+  }
+
+  public void notifySerializeCodeCache() {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        if (!isJSFrameworkInit())
+          return;
+
+        invokeExecJS("", null, METHOD_NOTIFY_SERIALIZE_CODE_CACHE, new WXJSObject[0]);
+      }
+    });
+  }
+
+  public void takeJSHeapSnapshot(String filename) {
+    Message msg = mJSHandler.obtainMessage();
+    msg.obj = filename;
+    msg.what = WXJSBridgeMsgType.TAKE_HEAP_SNAPSHOT;
+    msg.setTarget(mJSHandler);
+    msg.sendToTarget();
+  }
+
+  public static class TimerInfo {
+
+    public String callbackId;
+    public long time;
+    public String instanceId;
+  }
+
+  public int callCreateBody(String pageId, String componentType, String ref,
+                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
+                            float[] margins, float[] paddings, float[] borders) {
+
+    if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(componentType) || TextUtils.isEmpty(ref)) {
+      WXLogUtils.d("[WXBridgeManager] call callCreateBody arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(pageId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callCreateBody",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callCreateBody >>>> pageId:").append(pageId)
+              .append(", componentType:").append(componentType).append(", ref:").append(ref)
+              .append(", styles:").append(styles == null ? "{}" : styles.toString())
+              .append(", attributes:").append(attributes)
+              .append(", events:").append(events);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionCreateBody(instance, ref, componentType,
+                styles, attributes, events, margins, paddings, borders);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callCreateBody exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(pageId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callCreateBody",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callAddElement(String pageId, String componentType, String ref, int index, String parentRef,
+                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
+                            float[] margins, float[] paddings, float[] borders,boolean willLayout) {
+    if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(componentType) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callAddElement arguments is null");
+      }
+      WXExceptionUtils.commitCriticalExceptionRT(pageId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddElement",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callAddElement >>>> pageId:").append(pageId)
+              .append(", componentType:").append(componentType).append(", ref:").append(ref).append(", index:").append(index)
+              .append(", parentRef:").append(parentRef)
+              .append(", styles:").append(styles == null ? "{}" : styles.toString())
+              .append(", attributes:").append(attributes)
+              .append(", events:").append(events);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
+      if (instance != null) {
+        final GraphicActionAddElement action = new GraphicActionAddElement(instance, ref, componentType, parentRef, index,
+            styles, attributes, events, margins, paddings, borders);
+        if(willLayout) {
+          instance.addInActiveAddElementAction(ref, action);
+        }else{
+          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(pageId, action);
+        }
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callAddElement exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(pageId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddElement",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callRemoveElement(String instanceId, String ref) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callRemoveElement arguments is null");
+      }
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveElement",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callRemoveElement >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionRemoveElement(instance, ref);
+        if(instance.getInActiveAddElementAction(ref)!=null){
+          instance.removeInActiveAddElmentAction(ref);
+        }
+        else {
+          WXSDKManager.getInstance().getWXRenderManager()
+              .postGraphicAction(action.getPageId(), action);
+        }
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callRemoveElement exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveElement",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callMoveElement(String instanceId, String ref, String parentref, int index) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(parentref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callMoveElement arguments is null");
+      }
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callMoveElement",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callMoveElement >>>> instanceId:").append(instanceId)
+              .append(", parentref:").append(parentref)
+              .append(", index:").append(index)
+              .append(", ref:").append(ref);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionMoveElement(instance, ref, parentref, index);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callMoveElement exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callMoveElement",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callAddEvent(String instanceId, String ref, String event) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(event)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callAddEvent arguments is null");
+      }
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddEvent",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callAddEvent >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref)
+              .append(", event:").append(event);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        new GraphicActionAddEvent(instance, ref, event).executeActionOnRender();
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callAddEvent exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddEvent",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    // get next tick
+    getNextTick(instanceId);
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callRemoveEvent(String instanceId, String ref, String event) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(event)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callRemoveEvent arguments is null");
+      }
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveEvent",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callRemoveEvent >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref)
+              .append(", event:").append(event);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        new GraphicActionRemoveEvent(instance, ref, event).executeActionOnRender();
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callRemoveEvent exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveEvent",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    // get next tick
+    getNextTick(instanceId);
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callUpdateStyle(String instanceId, String ref, HashMap<String, Object> styles,
+                             HashMap<String, String> paddings,
+                             HashMap<String, String> margins,
+                             HashMap<String, String> borders) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callUpdateStyle arguments is null");
+      }
+
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateStyle",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callUpdateStyle >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref).append(", styles:").append(styles == null ? "{}" : styles.toString())
+              .append(", paddings:").append(paddings.toString())
+                      .append(", margins:").append(margins.toString())
+                              .append(", borders:").append(borders.toString());
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionUpdateStyle(instance, ref, styles, paddings, margins, borders);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callUpdateStyle exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateStyle",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callUpdateAttrs(String instanceId, String ref, HashMap<String, String> attrs) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callUpdateAttrs arguments is null");
+      }
+
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateAttrs",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callUpdateAttrs >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref).append(", attrs:").append(attrs.toString());
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionUpdateAttr(instance, ref, attrs);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callUpdateAttrs exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateAttrs",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  private void setExceedGPULimitComponentsInfo(String instanceId,String ref,GraphicSize layoutSize){
+    float limit = WXRenderManager.getOpenGLRenderLimitValue();
+    if(limit > 0 && (layoutSize.getHeight() > limit || layoutSize.getWidth() > limit)){
+      JSONObject ext = new JSONObject();
+      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instanceId,ref);
+      ext.put("GPU limit",String.valueOf(limit));
+      ext.put("component.width",String.valueOf(layoutSize.getWidth()));
+      ext.put("component.height",String.valueOf(layoutSize.getHeight()));
+      if (component.getComponentType() != null && !component.getComponentType().isEmpty()) {
+        ext.put("component.type", component.getComponentType());
+      }
+      if (component.getStyles() != null && !component.getStyles().isEmpty()) {
+        ext.put("component.style", component.getStyles().toString());
+      }
+      if (component.getAttrs() != null && !component.getAttrs().isEmpty()) {
+        ext.put("component.attr", component.getAttrs().toString());
+      }
+      if (component.getEvents() != null && !component.getEvents().isEmpty()) {
+        ext.put("component.event", component.getEvents().toString());
+      }
+      if (component.getMargin() != null) {
+        ext.put("component.margin", component.getMargin().toString());
+      }
+      if (component.getPadding() != null) {
+        ext.put("component.padding", component.getPadding().toString());
+      }
+      if (component.getBorder() != null) {
+        ext.put("component.border", component.getBorder().toString());
+      }
+      WXSDKManager.getInstance().getSDKInstance(instanceId).setComponentsInfoExceedGPULimit(ext);
+    }
+  }
+
+  public int callAddChildToRichtext(String instanceId, String nodeType, String ref, String parentRef, String richTextRef,
+                                    HashMap<String, String> styles, HashMap<String, String> attrs){
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callAddChildToRichtext arguments is null");
+      }
+
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddChildToRichtext",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callAddChildToRichtext >>>> instanceId:").append(instanceId)
+              .append(", nodeType:").append(nodeType).append(", ref:").append(ref).append(", parentRef:")
+              .append(parentRef).append(", richTextRef:").append(richTextRef).append(", styles:")
+              .append(styles.toString()).append(", attrs:").append(attrs.toString());
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionAddChildToRichtext(instance,nodeType,ref,parentRef,richTextRef,styles,attrs
+        );
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callAddChildToRichtext exception: ", WXLogUtils.getStackTrace(e));
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddChildToRichtext",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callRemoveChildFromRichtext(String instanceId, String ref, String parentRef, String richTextRef){
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callRemoveChildFromRichtext arguments is null");
+      }
+
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveChildFromRichtext",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callRemoveChildFromRichtext >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref).append(", parentRef:").append(parentRef).append(", richTextRef:").append(richTextRef);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionRemoveChildFromRichtext(instance, ref, parentRef, richTextRef);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callRemoveChildFromRichtext exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveChildFromRichtext",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callUpdateRichtextStyle(String instanceId, String ref, HashMap<String, String> styles, String parentRef, String richTextRef){
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callUpdateRichtextStyle arguments is null");
+      }
+
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateRichtextStyle",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callUpdateRichtextStyle >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref).append(", styles:").append(styles.toString()).append(", parentRef:")
+              .append(parentRef).append(", richTextRef:").append(richTextRef);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionUpdateRichtextStyle(instance, ref, styles, parentRef, richTextRef);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callUpdateRichtextStyle exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateRichtextStyle",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+  public int callUpdateRichtextChildAttr(String instanceId, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef){
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      if (WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("[WXBridgeManager] call callUpdateRichtextChildAttr arguments is null");
+      }
+
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateRichtextChildAttr",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callUpdateRichtextChildAttr >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref).append(", attrs:").append(attrs.toString()).append(", parentRef:")
+              .append(parentRef).append(", richTextRef:").append(richTextRef);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        final BasicGraphicAction action = new GraphicActionUpdateRichtextAttr(instance, ref, attrs, parentRef, richTextRef);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callUpdateRichtextChildAttr exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateRichtextChildAttr",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callLayout(String pageId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index) {
+
+    if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(ref)) {
+        if (WXEnvironment.isApkDebugable()){
+            WXLogUtils.d("[WXBridgeManager] call callLayout arguments is null");
+        }
+
+      WXExceptionUtils.commitCriticalExceptionRT(pageId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callLayout",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callLayout >>>> instanceId:").append(pageId)
+            .append(", ref:").append(ref).append(", height:").append(height).append(", width:").append(width)
+              .append(", top:").append(top)
+              .append(", bottom:").append(bottom)
+              .append(", left:").append(left)
+              .append(", right:").append(right);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
+      if (instance != null) {
+        GraphicSize size = new GraphicSize(width, height);
+        GraphicPosition position = new GraphicPosition(left, top, right, bottom);
+        setExceedGPULimitComponentsInfo(pageId,ref,size);
+        GraphicActionAddElement addAction = instance.getInActiveAddElementAction(ref);
+        if(addAction!=null) {
+          addAction.setRTL(isRTL);
+          addAction.setSize(size);
+          addAction.setPosition(position);
+          if(!TextUtils.equals(ref, WXComponent.ROOT)) {
+            addAction.setIndex(index);
+          }
+          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(pageId, addAction);
+          instance.removeInActiveAddElmentAction(ref);
+        }
+        else {
+          final BasicGraphicAction action = new GraphicActionLayout(instance, ref, position, size, isRTL);
+          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+        }
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callLayout exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(pageId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callLayout",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callAppendTreeCreateFinish(String instanceId, String ref) {
+
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
+      WXLogUtils.d("[WXBridgeManager] call callAppendTreeCreateFinish arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAppendTreeCreateFinish",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callAppendTreeCreateFinish >>>> instanceId:").append(instanceId)
+              .append(", ref:").append(ref);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      GraphicActionAppendTreeCreateFinish action = new GraphicActionAppendTreeCreateFinish(instance, ref);
+      WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callAppendTreeCreateFinish exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAppendTreeCreateFinish",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callCreateFinish(String instanceId) {
+
+    if (TextUtils.isEmpty(instanceId)) {
+      WXLogUtils.d("[WXBridgeManager] call callCreateFinish arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callCreateFinish",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callCreateFinish >>>> instanceId:").append(instanceId);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      long start = System.currentTimeMillis();
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        instance.getApmForInstance().onStage("callCreateFinish");
+        instance.firstScreenCreateInstanceTime(start);
+        GraphicActionCreateFinish action = new GraphicActionCreateFinish(instance);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callCreateFinish exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callCreateFinish",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public int callRenderSuccess(String instanceId) {
+
+    if (TextUtils.isEmpty(instanceId)) {
+      WXLogUtils.d("[WXBridgeManager] call callRenderSuccess arguments is null");
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRenderSuccess",
+              "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
+      return IWXBridge.INSTANCE_RENDERING_ERROR;
+    }
+
+    if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
+      mLodBuilder.append("[WXBridgeManager] callRenderSuccess >>>> instanceId:").append(instanceId);
+      WXLogUtils.d(mLodBuilder.substring(0));
+      mLodBuilder.setLength(0);
+    }
+
+    if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    try {
+      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+      if (instance != null) {
+        instance.getApmForInstance().onStage("callRenderSuccess");
+        GraphicActionRenderSuccess action = new GraphicActionRenderSuccess(instance);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXBridgeManager] callRenderSuccess exception: ", e);
+      WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+              WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRenderSuccess",
+              WXLogUtils.getStackTrace(e), null);
+    }
+
+    return IWXBridge.INSTANCE_RENDERING;
+  }
+
+  public ContentBoxMeasurement getMeasurementFunc(String instanceId, long renderObjectPtr) {
+    ContentBoxMeasurement contentBoxMeasurement = null;
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance != null) {
+      contentBoxMeasurement = instance.getContentBoxMeasurement(renderObjectPtr);
+    }
+    return contentBoxMeasurement;
+  }
+
+  public void bindMeasurementToRenderObject(long ptr){
+    if (isJSFrameworkInit()) {
+      mWXBridge.bindMeasurementToRenderObject(ptr);
+    }
+  }
+
+
+  /**
+   * Native: Layout
+   * @param instanceId
+   * @return
+   */
+  @UiThread
+  public boolean notifyLayout(String instanceId) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      return mWXBridge.notifyLayout(instanceId);
+    }
+    return false;
+  }
+
+  @UiThread
+  public void forceLayout(String instanceId) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.forceLayout(instanceId);
+    }
+  }
+
+  /**
+   * native: OnInstanceClose
+   * should be called on JSThread
+   * @param instanceId
+   */
+  public void onInstanceClose(String instanceId) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.onInstanceClose(instanceId);
+    }
+  }
+
+  /**
+   * native: SetDefaultHeightAndWidthIntoRootDom
+   * @param instanceId
+   * @param defaultWidth
+   * @param defaultHeight
+   */
+  public void setDefaultRootSize(final String instanceId, final float defaultWidth, final float defaultHeight, final boolean isWidthWrapContent, final boolean isHeightWrapContent) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setDefaultHeightAndWidthIntoRootDom(instanceId, defaultWidth, defaultHeight, isWidthWrapContent, isHeightWrapContent);
+    }
+  }
+
+  public void setRenderContentWrapContentToCore(boolean wrap, final String instanceId) {
+    if (isJSFrameworkInit()) {
+      mWXBridge.setRenderContainerWrapContent(wrap, instanceId);
+    }
+  }
+
+  public void setStyleWidth(String instanceId, String ref, float value) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setStyleWidth(instanceId, ref, value);
+    }
+  }
+
+  public void setStyleHeight(String instanceId, String ref, float value) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setStyleHeight(instanceId, ref, value);
+    }
+  }
+
+  public long[] getFirstScreenRenderTime(String instanceId) {
+    if (isJSFrameworkInit()) {
+      return mWXBridge.getFirstScreenRenderTime(instanceId);
+    }
+    return new long[]{0, 0, 0};
+  }
+
+  public long[] getRenderFinishTime(String instanceId) {
+    if (isJSFrameworkInit()) {
+      return mWXBridge.getRenderFinishTime(instanceId);
+    }
+    return new long[]{0, 0, 0};
+  }
+
+  public void setDeviceDisplay(final String instanceId, final float deviceWidth, final float deviceHeight, final float scale) {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        mWXBridge.setDeviceDisplay(instanceId, deviceWidth, deviceHeight, scale);
+      }
+    });
+  }
+
+  public void updateInitDeviceParams(final String width, final String height, final String density, final String statusHeight){
+    if(!isJSFrameworkInit()){
+      return;
+    }
+    post(new Runnable() {
+      @Override
+      public void run() {
+        mWXBridge.updateInitFrameworkParams(WXConfig.deviceWidth, width, WXConfig.deviceWidth);
+      }
+    });
+    post(new Runnable() {
+      @Override
+      public void run() {
+        mWXBridge.updateInitFrameworkParams(WXConfig.deviceHeight, height, WXConfig.deviceHeight);
+      }
+    });
+
+    post(new Runnable() {
+      @Override
+      public void run() {
+        mWXBridge.updateInitFrameworkParams(WXConfig.scale,  density, WXConfig.scale);
+      }
+    });
+
+    if(statusHeight != null){
+      post(new Runnable() {
+        @Override
+        public void run() {
+          mWXBridge.updateInitFrameworkParams(WXConfig.androidStatusBarHeight,  statusHeight, WXConfig.androidStatusBarHeight);
+        }
+      });
+    }
+  }
+
+  public void setMargin(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setMargin(instanceId, ref, edge, value);
+    }
+  }
+
+  public void setPadding(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setPadding(instanceId, ref, edge, value);
+    }
+  }
+
+  public void setPosition(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setPosition(instanceId, ref, edge, value);
+    }
+  }
+
+  public void markDirty(String instanceId, String ref, boolean dirty) {
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.markDirty(instanceId, ref, dirty);
+    }
+  }
+  public void setViewPortWidth(String instanceId,float viewPortWidth){
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setViewPortWidth(instanceId,viewPortWidth);
+    }
+  }
+  public void setPageArgument(String instanceId,String key,String value){
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setPageArgument(instanceId,key,value);
+    }
+  }
+  public void reloadPageLayout(String instanceId){
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.reloadPageLayout(instanceId);
+    }
+  }
+
+  public void setDeviceDisplayOfPage(String instanceId,float width,float height){
+    if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
+      mWXBridge.setDeviceDisplayOfPage(instanceId,width,height);
+    }
+  }
+
+  public int callHasTransitionPros(String instanceId, String ref, HashMap<String, String> styles) {
+    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instanceId, ref);
+    if (null == component || null == component.getTransition() || null == component.getTransition().getProperties()) {
+      return IWXBridge.DESTROY_INSTANCE;
+    }
+
+    for(String property : component.getTransition().getProperties()){
+      if(styles.containsKey(property)){
+        return IWXBridge.INSTANCE_RENDERING;
+      }
+    }
+    return IWXBridge.INSTANCE_RENDERING_ERROR;
+  }
+
+  public void registerCoreEnv(String key, String value) {
+    if (isJSFrameworkInit())
+      mWXBridge.registerCoreEnv(key, value);
+    else
+      mWeexCoreEnvOptions.put(key, value);
+  }
+
+  private void onJsFrameWorkInitSuccees() {
+    for (Map.Entry<String, String> entry : mWeexCoreEnvOptions.entrySet()) {
+      mWXBridge.registerCoreEnv(entry.getKey(), entry.getValue());
+    }
+    mWeexCoreEnvOptions.clear();
+  }
+
+  public  String getWeexCoreThreadStackTrace(){
+    if (null == mJSThread){
+      return "null == mJSThread";
+    }
+    StringBuilder stringBuilder = new StringBuilder();
+
+    try {
+      stringBuilder.append(String.format("Thread Name: '%s'\n", mJSThread.getName()));
+      stringBuilder.append(String.format(Locale.ENGLISH,"\"%s\" prio=%d tid=%d %s\n", mJSThread.getName(), mJSThread.getPriority(), mJSThread.getId(), mJSThread.getState()));
+
+      for (StackTraceElement e: mJSThread.getStackTrace()){
+        stringBuilder.append(String.format("\tat %s\n", e.toString()));
+      }
+    } catch (Exception var8) {
+      Log.e("weex", "getJSThreadStackTrace error:", var8);
+    }
+    return stringBuilder.toString();
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXDebugJsBridge.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXDebugJsBridge.java
new file mode 100644
index 0000000..bed2a43
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXDebugJsBridge.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.weex.utils.WXWsonJSONSwitch;
+import org.apache.weex.wson.WsonUtils;
+
+/**
+ * Created by darin on 27/03/2018.
+ */
+
+public class WXDebugJsBridge {
+
+    public native void resetWXBridge(Object bridge, String className);
+
+    public native void jsHandleSetJSVersion(String jsVersion);
+
+    public native void jsHandleReportException(String instanceId, String func, String exceptionString);
+
+    public native void jsHandleCallNative(String instanceId, byte[] tasks, String callback);
+
+    public void jsHandleCallNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options) {
+        jsHandleCallNativeModule(instanceId, module, method,
+                WXWsonJSONSwitch.convertJSONToWsonIfUseWson(arguments), WXWsonJSONSwitch.convertJSONToWsonIfUseWson(options), true);
+    }
+
+    public native void jsHandleCallNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options, boolean h5);
+
+    public void jsHandleCallNativeComponent(String instanceId, String componentRef, String method, byte[] arguments, byte[] options){
+        jsHandleCallNativeComponent(instanceId, componentRef, method, WXWsonJSONSwitch.convertJSONToWsonIfUseWson(arguments), WXWsonJSONSwitch.convertJSONToWsonIfUseWson(options), true);
+    }
+
+
+    public native void jsHandleCallNativeComponent(String instanceId, String componentRef, String method, byte[] arguments, byte[] options, boolean from);
+
+    public void jsHandleCallAddElement(String instanceId, String ref, String dom, String index){
+        jsHandleCallAddElement(instanceId, ref, WsonUtils.toWson(JSON.parse(dom)), index, true);
+    }
+
+    public native void jsHandleCallAddElement(String instanceId, String ref, byte[] dom, String index, boolean h5);
+
+    public native void jsHandleSetTimeout(String callbackId, String time);
+
+    public native void jsHandleCallNativeLog(byte[] str_array);
+
+    public void jsHandleCallCreateBody(String pageId, String domStr){
+        jsHandleCallCreateBody(pageId, WsonUtils.toWson(JSON.parse(domStr)), true);
+    }
+
+    public native void jsHandleCallCreateBody(String pageId, byte[] domStr, boolean h5);
+
+    public native void jsHandleCallUpdateFinish(String instanceId, byte[] tasks, String callback);
+
+    public native void jsHandleCallCreateFinish(String pageId);
+
+    public native void jsHandleCallRefreshFinish(String instanceId, byte[] tasks, String callback);
+
+    public void jsHandleCallUpdateAttrs(String pageId, String ref, String data){
+        jsHandleCallUpdateAttrs(pageId, ref, WsonUtils.toWson(JSON.parseObject(data)), true);
+    }
+
+    public native void jsHandleCallUpdateAttrs(String pageId, String ref, byte[] data, boolean h5);
+
+    public void jsHandleCallUpdateStyle(String pageId, String ref, String data){
+        byte[] data1 = WsonUtils.toWson(JSON.parseObject(data));
+        jsHandleCallUpdateStyleNative(pageId, ref, data1, true);
+    }
+
+    public native void jsHandleCallUpdateStyleNative(String pageId, String ref, byte[] data, boolean h5);
+
+    public native void jsHandleCallRemoveElement(String pageId, String ref);
+
+    public native void jsHandleCallMoveElement(String pageId, String ref, String parentRef, String index_str);
+
+    public native void jsHandleCallAddEvent(String pageId, String ref, String event);
+
+    public native void jsHandleCallRemoveEvent(String pageId, String ref, String event);
+
+    public native void jsHandleSetInterval(String instanceId, String callbackId, String time);
+
+    public native void jsHandleClearInterval(String instanceId, String callbackId);
+
+    public native void jsHandleCallGCanvasLinkNative(String contextId, int type, String val);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXHashMap.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXHashMap.java
new file mode 100644
index 0000000..68ca5e2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXHashMap.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import android.text.TextUtils;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+/**
+ * HashMap for Weex
+ */
+public class WXHashMap<K, V> extends HashMap<K, V> {
+
+  private static final long serialVersionUID = 4294272345728974369L;
+
+  private Stack<String> instancesStack = new Stack<String>();
+  private String mTag;
+
+  @Override
+  public V put(K key, V value) {
+    if (key != null && key.toString() != null) {
+      if (instancesStack.contains(key)) {
+        instancesStack.remove(key);
+      }
+      instancesStack.push(key.toString());
+    }
+    return super.put(key, value);
+  }
+
+  @Override
+  public V remove(Object key) {
+    return super.remove(key);
+  }
+
+  public V removeFromMapAndStack(Object key) {
+    instancesStack.remove(key);
+    return super.remove(key);
+  }
+
+  /**
+   * Get instance Id of the top of the stack
+   *
+   * @return
+   */
+  public String getStackTopInstanceId() {
+    return instancesStack.isEmpty() ? "" : instancesStack.pop();
+  }
+
+  /**
+   * Move instanceId to the top of the stack
+   *
+   * @param id
+   */
+  public void setStackTopInstance(String id) {
+    if (!TextUtils.isEmpty(id)) {
+      instancesStack.remove(id);
+      instancesStack.push(id);
+    }
+  }
+
+  public Stack<String> getInstanceStack() {
+    return instancesStack;
+  }
+
+  public String getTag() {
+    return mTag;
+  }
+
+  public void setTag(String tag) {
+    this.mTag = tag;
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXJSObject.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXJSObject.java
new file mode 100644
index 0000000..7642cad
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXJSObject.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+
+import org.apache.weex.utils.WXJsonUtils;
+
+public class WXJSObject {
+
+    public static final int NUMBER = 1;
+    public static final int String = 2;
+    public static final int JSON = 3;
+    public static final int WSON = 4;
+
+    public Object data;
+    public int type;
+    public String key;
+
+    public WXJSObject(int type, Object data) {
+        this.type = type;
+        this.data = data;
+    }
+
+    public WXJSObject(int type, Object data, String key) {
+        this.type = type;
+        this.data = data;
+        this.key = key;
+    }
+
+    public WXJSObject(Object object) {
+
+        if(null == object){
+            type= String;
+            data = "";
+            return;
+        }
+
+        data = object;
+        if (object instanceof Integer) {
+            type = NUMBER;
+            data = (double) (Integer) object;
+        } else if (object instanceof Double) {
+            type = NUMBER;
+        } else if (object instanceof Float) {
+            type = NUMBER;
+            data = (double) ((Float) object).intValue();
+        } else if (object instanceof String) {
+            type = String;
+        } else if (object instanceof Object) {
+            type = JSON;
+            data = WXJsonUtils.fromObjectToJSONString(object,true);
+        }
+    }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXModuleManager.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXModuleManager.java
new file mode 100644
index 0000000..25fdbe6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXModuleManager.java
@@ -0,0 +1,535 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import android.content.Intent;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.view.Menu;
+
+import com.alibaba.fastjson.JSONArray;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.common.Destroyable;
+import org.apache.weex.common.WXException;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.ui.config.ConfigModuleFactory;
+import org.apache.weex.ui.module.WXDomModule;
+import org.apache.weex.ui.module.WXTimerModule;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.cache.RegisterCache;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.weex.utils.cache.RegisterCache.ModuleCache;
+
+/**
+ * Manager class for weex module. There are two types of modules in weex, one is instance-level module,
+ * the other is global-level module. Instance-level module will be created every time an instance
+ * is created, while global-level module will be singleton in {@link WXSDKEngine}.
+ */
+public class WXModuleManager {
+
+  /**
+   * module class object dictionary
+   */
+  private static volatile ConcurrentMap<String, ModuleFactoryImpl> sModuleFactoryMap = new ConcurrentHashMap<>();
+  private static Map<String, WXModule> sGlobalModuleMap = new HashMap<>();
+  private static Map<String, WXDomModule> sDomModuleMap = new HashMap<>();
+
+
+  /**
+   * module object dictionary
+   * K : instanceId, V : Modules
+   */
+  private static Map<String, Map<String, WXModule>> sInstanceModuleMap = new ConcurrentHashMap<>();
+
+
+  public static boolean registerModule(Map<String, ModuleCache> moduleCacheMap) {
+    if (moduleCacheMap.isEmpty())
+      return true;
+
+    final Iterator<Entry<String, ModuleCache>> iterator = moduleCacheMap.entrySet().iterator();
+    WXBridgeManager.getInstance()
+            .postWithName(new Runnable() {
+              @Override
+              public void run() {
+                Map<String, Object> modules = new HashMap<>();
+
+                while (iterator.hasNext()) {
+                  Entry<String, ModuleCache> next = iterator.next();
+                  ModuleCache value = next.getValue();
+                  String moduleName = value.name;
+                  if (TextUtils.equals(moduleName, WXDomModule.WXDOM)) {
+                    WXLogUtils.e("Cannot registered module with name 'dom'.");
+                    continue;
+                  }
+
+                  if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) {
+                    WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);
+                  }
+                  ModuleFactory factory = value.factory;
+                  try {
+                    registerNativeModule(moduleName, factory);
+                  } catch (WXException e) {
+                    WXLogUtils.e("registerNativeModule" + e);
+                  }
+
+                  if (value.global) {
+                    try {
+                      WXModule wxModule = factory.buildInstance();
+                      wxModule.setModuleName(moduleName);
+                      sGlobalModuleMap.put(moduleName, wxModule);
+                    } catch (Exception e) {
+                      WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e);
+                    }
+                  }
+
+                  try {
+                    sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
+                  } catch (Throwable e) {
+
+                  }
+                  modules.put(moduleName, factory.getMethods());
+                }
+                WXSDKManager.getInstance().registerModules(modules);
+              }
+            },null,"registerModule From Cache");
+    return true;
+  }
+
+  /**
+   * Register module to JavaScript and Android
+   */
+  public static boolean registerModule(final String moduleName, final ModuleFactory factory, final boolean global) throws WXException {
+    if (moduleName == null || factory == null) {
+      return false;
+    }
+
+    if (TextUtils.equals(moduleName,WXDomModule.WXDOM)) {
+      WXLogUtils.e("Cannot registered module with name 'dom'.");
+      return false;
+    }
+
+    if(RegisterCache.getInstance().cacheModule(moduleName,factory,global)) {
+      return true;
+    }
+
+    //execute task in js thread to make sure register order is same as the order invoke register method.
+    WXBridgeManager.getInstance()
+            .postWithName(new Runnable() {
+              @Override
+              public void run() {
+                if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) {
+                  WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);
+                }
+                try {
+                  registerNativeModule(moduleName, factory);
+                } catch (WXException e) {
+                  WXLogUtils.e("registerNativeModule" + e);
+                }
+
+                if (global) {
+                  try {
+                    WXModule wxModule = factory.buildInstance();
+                    wxModule.setModuleName(moduleName);
+                    sGlobalModuleMap.put(moduleName, wxModule);
+                  } catch (Exception e) {
+                    WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e);
+                  }
+                }
+
+                registerJSModule(moduleName, factory);
+
+                try {
+                  sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
+                } catch (Throwable e) {
+
+                }
+              }
+            },null,"registerModule");
+    return true;
+
+  }
+
+  static boolean registerNativeModule(String moduleName, ModuleFactory factory) throws WXException {
+    if (factory == null) {
+      return false;
+    }
+
+    try {
+      if (!sModuleFactoryMap.containsKey(moduleName) ) {
+        sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
+      }
+    }catch (ArrayStoreException e){
+      e.printStackTrace();
+      //ignore:
+      //may throw this exception:
+      //java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
+
+      WXLogUtils.e("[WXModuleManager] registerNativeModule Error moduleName:"  + moduleName + " Error:" + e.toString());
+    }
+    return true;
+  }
+
+  static boolean registerJSModule(String moduleName, ModuleFactory factory) {
+    Map<String, Object> modules = new HashMap<>();
+    modules.put(moduleName, factory.getMethods());
+    WXSDKManager.getInstance().registerModules(modules);
+    return true;
+  }
+
+  static Object callModuleMethod(final String instanceId, String moduleStr, String methodStr, JSONArray args) {
+    ModuleFactory factory = sModuleFactoryMap.get(moduleStr).mFactory;
+    if(factory == null){
+      WXLogUtils.e("[WXModuleManager] module factory not found.");
+      return null;
+    }
+    final WXModule wxModule = findModule(instanceId, moduleStr,factory);
+    if (wxModule == null) {
+      return null;
+    }
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    wxModule.mWXSDKInstance = instance;
+
+    final Invoker invoker = factory.getMethodInvoker(methodStr);
+    try {
+      if(instance != null) {
+        IWXUserTrackAdapter userTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
+        if(userTrackAdapter != null) {
+          HashMap<String, Serializable> data = new HashMap<String, Serializable>();
+          data.put(IWXUserTrackAdapter.MONITOR_ERROR_CODE, "101");
+          data.put(IWXUserTrackAdapter.MONITOR_ARG, moduleStr + "." + methodStr);
+          data.put(IWXUserTrackAdapter.MONITOR_ERROR_MSG, instance.getBundleUrl());
+          userTrackAdapter.commit(instance.getContext(), null, IWXUserTrackAdapter.INVOKE_MODULE, null, data);
+        }
+        return dispatchCallModuleMethod(instance,wxModule,args,invoker);
+      } else {
+        WXLogUtils.e("callModuleMethod >>> instance is null");
+        return null;
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("callModuleMethod >>> invoke module:" + moduleStr + ", method:" + methodStr + " failed. ", e);
+      return null;
+    } finally {
+      if (wxModule instanceof WXDomModule || wxModule instanceof WXTimerModule) {
+        wxModule.mWXSDKInstance = null;
+      }
+    }
+  }
+
+  private static Object dispatchCallModuleMethod(@NonNull WXSDKInstance instance, @NonNull WXModule wxModule,
+                                                 @NonNull JSONArray args, @NonNull Invoker invoker) throws Exception{
+    if(!instance.isPreRenderMode()) {
+      return instance.getNativeInvokeHelper().invoke(wxModule,invoker,args);
+    }
+    // we are in preRender mode
+    if(invoker.isRunOnUIThread()) {/*ASYNC CALL*/
+//      DOMAction moduleInvocationAction = Actions.getModuleInvocationAction(wxModule,args,invoker);
+//      WXSDKManager.getInstance().getWXDomManager().postAction(instance.getInstanceId(), moduleInvocationAction,false);
+      return null;
+    } else {/*SYNC CALL*/
+      return instance.getNativeInvokeHelper().invoke(wxModule,invoker,args);
+    }
+  }
+
+  public static boolean hasModule(String module) {
+    return sGlobalModuleMap.containsKey(module) || sModuleFactoryMap.containsKey(module);
+  }
+
+  private static WXModule findModule(String instanceId, String moduleStr,ModuleFactory factory) {
+    // find WXModule
+    WXModule wxModule = sGlobalModuleMap.get(moduleStr);
+
+    //not global module
+    if (wxModule == null) {
+      Map<String, WXModule> moduleMap = sInstanceModuleMap.get(instanceId);
+      if (moduleMap == null) {
+        moduleMap = new ConcurrentHashMap<>();
+        sInstanceModuleMap.put(instanceId, moduleMap);
+      }
+      // if cannot find the Module, create a new Module and save it
+      wxModule = moduleMap.get(moduleStr);
+      if (wxModule == null) {
+        try {
+          if(factory instanceof ConfigModuleFactory){
+            WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+            wxModule = ((ConfigModuleFactory) factory).buildInstance(instance);
+          }else{
+            wxModule = factory.buildInstance();
+          }
+          wxModule.setModuleName(moduleStr);
+        } catch (Exception e) {
+          WXLogUtils.e(moduleStr + " module build instace failed.", e);
+          return null;
+        }
+        moduleMap.put(moduleStr, wxModule);
+      }
+    }
+
+    return wxModule;
+  }
+
+  /**Hook Activity life cycle callback begin***/
+
+
+  public static void onActivityCreate(String instanceId){
+
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onActivityCreate();
+        } else {
+          WXLogUtils.w("onActivityCreate can not find the " + key + " module");
+        }
+      }
+    }
+
+  }
+
+  public static void onActivityStart(String instanceId){
+
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onActivityStart();
+        } else {
+          WXLogUtils.w("onActivityStart can not find the " + key + " module");
+        }
+      }
+    }
+  }
+
+  public static void onActivityPause(String instanceId){
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onActivityPause();
+        } else {
+          WXLogUtils.w("onActivityPause can not find the " + key + " module");
+        }
+      }
+    }
+  }
+
+  public static void onActivityResume(String instanceId){
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onActivityResume();
+        } else {
+          WXLogUtils.w("onActivityResume can not find the " + key + " module");
+        }
+      }
+    }
+  }
+
+  public static void onActivityStop(String instanceId){
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onActivityStop();
+        } else {
+          WXLogUtils.w("onActivityStop can not find the " + key + " module");
+        }
+      }
+    }
+  }
+
+  public static void onActivityDestroy(String instanceId){
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onActivityDestroy();
+        } else {
+          WXLogUtils.w("onActivityDestroy can not find the " + key + " module");
+        }
+      }
+    }
+  }
+
+  public static boolean onActivityBack(String instanceId){
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          return module.onActivityBack();
+        } else {
+          WXLogUtils.w("onActivityCreate can not find the " + key + " module");
+        }
+      }
+    }
+    return false;
+  }
+
+  public static void onActivityResult(String instanceId,int requestCode, int resultCode, Intent data){
+
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onActivityResult(requestCode, resultCode, data);
+        } else {
+          WXLogUtils.w("onActivityResult can not find the " + key + " module");
+        }
+      }
+    }
+  }
+
+  public static boolean onCreateOptionsMenu(String instanceId,Menu menu) {
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onCreateOptionsMenu(menu);
+        } else {
+          WXLogUtils.w("onActivityResult can not find the " + key + " module");
+        }
+      }
+    }
+    return false;
+  }
+
+  public static void onRequestPermissionsResult(String instanceId ,int requestCode, String[] permissions, int[] grantResults) {
+    Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId);
+    if(modules!=null) {
+      for (String key : modules.keySet()) {
+        WXModule module = modules.get(key);
+        if (module != null) {
+          module.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        } else {
+          WXLogUtils.w("onActivityResult can not find the " + key + " module");
+        }
+      }
+    }
+  }
+
+  public static void destroyInstanceModules(String instanceId) {
+    sDomModuleMap.remove(instanceId);
+    Map<String, WXModule> moduleMap = sInstanceModuleMap.remove(instanceId);
+    if (moduleMap == null || moduleMap.size() < 1) {
+      return;
+    }
+    Iterator<Entry<String, WXModule>> iterator = moduleMap.entrySet().iterator();
+    Entry<String, WXModule> entry;
+    while (iterator.hasNext()) {
+      entry = iterator.next();
+      WXModule module = entry.getValue();
+      if(module instanceof Destroyable){
+        ((Destroyable)module).destroy();
+      }
+
+    }
+  }
+
+  public static void createDomModule(WXSDKInstance instance){
+    if(instance != null) {
+      sDomModuleMap.put(instance.getInstanceId(), new WXDomModule(instance));
+    }
+  }
+
+  public static void destoryDomModule(String instanceID){
+    sDomModuleMap.remove(instanceID);
+  }
+
+  public static WXDomModule getDomModule(String instanceId){
+    return sDomModuleMap.get(instanceId);
+  }
+
+  public static void reload(){
+    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
+      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
+        try {
+          registerJSModule(entry.getKey(), entry.getValue().mFactory);
+        } catch (Throwable e) {
+
+        }
+      }
+    }
+  }
+
+  /**
+   * registerWhenCreateInstance
+   */
+  public static void registerWhenCreateInstance(){
+    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
+      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
+        try {
+          if (!entry.getValue().hasRigster) {
+            registerJSModule(entry.getKey(), entry.getValue().mFactory);
+          }
+        } catch (Throwable e) {
+
+        }
+      }
+    }
+  }
+
+  /**
+   * resetAllModuleState
+   */
+  public static void resetAllModuleState() {
+    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
+      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
+        entry.getValue().hasRigster = false;
+      }
+    }
+  }
+
+  /**
+   * resetModuleState
+   * @param module
+   * @param state
+   */
+  public static void resetModuleState(String module, boolean state) {
+    if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) {
+      for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) {
+        try {
+          if (entry.getKey() != null && entry.getKey().equals(module)) {
+            entry.getValue().hasRigster = state;
+          }
+        } catch (Throwable e) {
+
+        }
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXParams.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXParams.java
new file mode 100644
index 0000000..7f2c265
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXParams.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.base.CalledByNative;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+public class WXParams implements Serializable {
+
+  private String platform;
+  private String osVersion;
+  private String appVersion;
+  private String weexVersion;
+  private String deviceModel;
+  private String appName;
+  private String deviceWidth;
+  private String deviceHeight;
+  private String shouldInfoCollect;
+  private String logLevel;
+  private String needInitV8;
+  private String cacheDir;
+  private String useSingleProcess;
+  private String crashFilePath;
+  private String libJssPath;
+  private String layoutDirection;
+
+  private String libJscPath;
+  private String libIcuPath;
+  private String libLdPath;
+  private String libJsbPath;
+
+  private Map<String, String> options;
+
+  @CalledByNative
+  public Object getOptions() {
+    return options;
+  }
+
+  public void setOptions(Map<String, String> options) {
+    this.options = options;
+  }
+
+  public String getShouldInfoCollect() {
+    return shouldInfoCollect;
+  }
+
+  public void setShouldInfoCollect(String shouldInfoCollect) {
+    this.shouldInfoCollect = shouldInfoCollect;
+  }
+
+  @CalledByNative
+  public String getPlatform() {
+    return platform;
+  }
+
+  public void setPlatform(String platform) {
+    this.platform = platform;
+  }
+
+  public void setCacheDir(String cache) {
+    this.cacheDir = cache;
+  }
+
+  @CalledByNative
+  public String getCacheDir() {
+    return this.cacheDir;
+  }
+
+  @CalledByNative
+  public String getOsVersion() {
+    return osVersion;
+  }
+
+  public void setOsVersion(String osVersion) {
+    this.osVersion = osVersion;
+  }
+
+  @CalledByNative
+  public String getAppVersion() {
+    return appVersion;
+  }
+
+  public void setAppVersion(String appVersion) {
+    this.appVersion = appVersion;
+  }
+
+  @CalledByNative
+  public String getWeexVersion() {
+    return weexVersion;
+  }
+
+  public void setWeexVersion(String weexVersion) {
+    this.weexVersion = weexVersion;
+  }
+
+  @CalledByNative
+  public String getDeviceModel() {
+    return deviceModel;
+  }
+
+  public void setDeviceModel(String deviceModel) {
+    this.deviceModel = deviceModel;
+  }
+
+  @CalledByNative
+  public String getLayoutDirection() {return layoutDirection;}
+
+  public void setLayoutDirection(String direction) { this.layoutDirection = direction; }
+
+  @CalledByNative
+  public String getAppName() {
+    return appName;
+  }
+
+  public void setAppName(String appName) {
+    this.appName = appName;
+  }
+
+  @CalledByNative
+  public String getDeviceWidth() {
+    return deviceWidth;
+  }
+
+  @CalledByNative
+  public boolean getReleaseMap() {
+    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+    if (null == adapter){
+      return false;
+    }
+    String doRelease = adapter.getConfigWhenInit("wxapm","release_map","true");
+    WXLogUtils.e("getReleaseMap:"+doRelease);
+    return "true".equalsIgnoreCase(doRelease);
+  }
+
+
+  /**
+   * Device should not be set manually, instead it suppose to represent the width of device and
+   * initialized automatically.
+   * @param deviceWidth
+   */
+  @Deprecated
+  public void setDeviceWidth(String deviceWidth) {
+    this.deviceWidth = deviceWidth;
+  }
+
+  @CalledByNative
+  public String getDeviceHeight() {
+    return deviceHeight;
+  }
+
+  public void setDeviceHeight(String deviceHeight) {
+    this.deviceHeight = deviceHeight;
+  }
+
+  public String getLogLevel() {
+    if(logLevel == null){
+      return "";
+    }
+    return logLevel;
+  }
+
+  @CalledByNative
+  public String getUseSingleProcess() {
+    WXLogUtils.e("getUseSingleProcess is running " + useSingleProcess);
+    return useSingleProcess;
+  }
+
+  public void setUseSingleProcess(String useSingleProcess) {
+    this.useSingleProcess = useSingleProcess;
+  }
+
+  public void setLogLevel(String logLevel) {
+    this.logLevel = logLevel;
+  }
+
+  public String getNeedInitV8() {
+    if(needInitV8 ==null){
+      return "";
+    }
+    return this.needInitV8;
+  }
+
+  public void setNeedInitV8(boolean need) {
+    if (need) {
+      this.needInitV8 = "1";
+    } else {
+      this.needInitV8 = "0";
+    }
+  }
+
+  public void setCrashFilePath(String crashFilePath) {
+    WXLogUtils.e("WXParams","setCrashFilePath: " + crashFilePath);
+    this.crashFilePath = crashFilePath;
+  }
+
+  @CalledByNative
+  public String getCrashFilePath() {
+    WXLogUtils.e("WXParams", "getCrashFilePath:" + crashFilePath);
+    return this.crashFilePath;
+  }
+
+  @CalledByNative
+  public String getLibJssPath() {
+    WXLogUtils.e("getLibJssPath is running " + libJssPath);
+    return libJssPath;
+  }
+
+  @CalledByNative
+  public String getLibJsbPath() {
+    WXLogUtils.e("getLibJsbPath is running " + libJsbPath);
+    return libJsbPath;
+  }
+
+  public void setLibJsbPath(String libJsbPath) {
+    this.libJsbPath = libJsbPath;
+  }
+
+  @CalledByNative
+  public String getLibJscPath() {
+    WXLogUtils.e("getLibJscPath is running " + libJscPath);
+    return libJscPath;
+  }
+  public void setLibJscPath(String libJscPath) {
+    this.libJscPath = libJscPath;
+  }
+  public void setLibJssPath(String libJssPath) {
+    this.libJssPath = libJssPath;
+  }
+  @CalledByNative
+  public String getLibIcuPath() {
+    WXLogUtils.e("getLibIcuPath is running " + libIcuPath);
+    return libIcuPath;
+  }
+
+  public void setLibIcuPath(String libIcuPath) {
+    this.libIcuPath = libIcuPath;
+  }
+
+  @CalledByNative
+  public String getLibLdPath() {
+    WXLogUtils.e("getLibLdPath is running " + libLdPath);
+    return libLdPath;
+  }
+
+  public void setLibLdPath(String libLdPath) {
+    this.libLdPath = libLdPath;
+  }
+
+  @CalledByNative
+  public String getUseRunTimeApi() {
+    return String.valueOf(WXEnvironment.sUseRunTimeApi);
+  }
+
+  public Map<String, Object> toMap() {
+    HashMap<String, Object> map  = new HashMap<>();
+    map.put("appName", appName);
+    map.put("appVersion", appVersion);
+    map.put("cacheDir", cacheDir);
+    map.put("deviceHeight", deviceHeight);
+    map.put("deviceModel", deviceModel);
+    map.put("deviceWidth", deviceWidth);
+    map.put("layoutDirection", layoutDirection);
+    map.put("libJssPath", libJssPath);
+    map.put("logLevel", logLevel);
+    map.put("needInitV8", needInitV8);
+    map.put("osVersion", osVersion);
+    map.put("platform", platform);
+    map.put("useSingleProcess", useSingleProcess);
+    map.put("shouldInfoCollect", shouldInfoCollect);
+    map.put("weexVersion", weexVersion);
+    map.put("crashFilePath", crashFilePath);
+    map.put("libJscPath", libJscPath);
+    map.put("libIcuPath", libIcuPath);
+    map.put("libLdPath", libLdPath);
+    map.put("options", options);
+    map.put("useRunTimeApi",WXEnvironment.sUseRunTimeApi);
+    map.put("__enable_native_promise__",!WXEnvironment.sUseRunTimeApi);
+    return map;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXServiceManager.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXServiceManager.java
new file mode 100644
index 0000000..69ab29a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXServiceManager.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import android.text.TextUtils;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.common.WXJSService;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class WXServiceManager {
+
+    private static volatile ConcurrentHashMap<String, WXJSService> sInstanceJSServiceMap = new ConcurrentHashMap<>();
+
+    public static boolean registerService(String name, String serviceScript, Map<String, Object> options) {
+        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(serviceScript)) return false;
+
+        String param1 = "register: global.registerService, unregister: global.unregisterService";
+        String param2 = "serviceName: \"" + name + "\"";
+        for (String key: options.keySet()) {
+            // TODO - why always string?
+            Object value = options.get(key);
+            if (value instanceof  String) {
+                param2 += ", \'" + key + "\': \'" + value + "\'";
+            } else {
+                param2 += ", \'" + key + "\': " + value;
+            }
+        }
+        String serviceJs = String.format(";(function(service, options){ ;%s; })({ %s }, { %s });", serviceScript, param1, param2);
+
+        WXJSService service = new WXJSService();
+        service.setName(name);
+        service.setScript(serviceScript);
+        service.setOptions(options);
+        sInstanceJSServiceMap.put(name, service);
+
+        WXBridgeManager.getInstance().execJSService(serviceJs);
+        return true;
+    }
+
+    public static boolean unRegisterService(String name) {
+        if (TextUtils.isEmpty(name)) return false;
+
+        if(WXEnvironment.isApkDebugable()) {
+            sInstanceJSServiceMap.remove(name);
+        }
+
+        String js = String.format("global.unregisterService( \"%s\" );", name);
+        WXBridgeManager.getInstance().execJSService(js);
+        return true;
+    }
+
+
+    public static void execAllCacheJsService() {
+        for (String serviceName: sInstanceJSServiceMap.keySet()) {
+            WXJSService service = sInstanceJSServiceMap.get(serviceName);
+            registerService(service.getName(), service.getScript(), service.getOptions());
+        }
+    }
+
+    public static WXJSService getService(String serviceName) {
+        if (sInstanceJSServiceMap != null) {
+            return sInstanceJSServiceMap.get(serviceName);
+        }
+        return null;
+    }
+
+    public static void reload() {
+        if(sInstanceJSServiceMap != null && sInstanceJSServiceMap.size() > 0) {
+            WXBridgeManager.getInstance().post(new Runnable() {
+                @Override
+                public void run() {
+                    for (Map.Entry<String, WXJSService> entry : sInstanceJSServiceMap.entrySet()) {
+                        WXJSService service = entry.getValue();
+                        registerService(service.getName(), service.getScript(), service.getOptions());
+                    }
+                }
+            });
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXTask.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXTask.java
new file mode 100644
index 0000000..3f5e526
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXTask.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import org.apache.weex.common.IWXObject;
+
+import java.util.ArrayList;
+
+/**
+ * Weex JS Native task
+ */
+public class WXTask implements IWXObject {
+
+  /**
+   * Native module
+   */
+  public String module;
+
+  /**
+   * The method of native module
+   */
+  public String method;
+
+  /**
+   * The method parameters
+   */
+  public ArrayList<String> args;
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXValidateProcessor.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXValidateProcessor.java
new file mode 100644
index 0000000..f167835
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXValidateProcessor.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.bridge;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by fengjunjie
+ */
+public interface WXValidateProcessor {
+
+    WXModuleValidateResult onModuleValidate(WXSDKInstance wxsdkInstance, String moduleStr,
+                                            String methodStr, JSONArray params,
+                                            JSONObject options);
+
+    WXComponentValidateResult onComponentValidate(WXSDKInstance wxsdkInstance,
+                                                  String componentName,
+                                                  WXComponent parentComponent);
+
+    boolean needValidate(String bundleUrl);
+
+    class WXComponentValidateResult {
+
+        public boolean isSuccess;
+
+        public String replacedComponent;
+
+        public JSONObject validateInfo;
+
+    }
+
+    class WXModuleValidateResult {
+
+        public boolean isSuccess;
+
+        public JSONObject validateInfo;
+
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/Constants.java b/android/sdk/src/main/java/org/apache/weex/common/Constants.java
new file mode 100644
index 0000000..d3d3232
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/Constants.java
@@ -0,0 +1,388 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public class Constants {
+
+  public interface Orientation {
+
+    int HORIZONTAL = 0;
+    int VERTICAL = 1;
+  }
+
+  public interface Weex {
+    String REF = "ref";
+    String INSTANCEID = "instanceid";
+    String TYPE = "type";
+  }
+
+  public interface Name {
+
+    String DEFAULT_WIDTH = "defaultWidth";
+    String DEFAULT_HEIGHT = "defaultHeight";
+    String HREF = "href";
+    String WIDTH = "width";
+    String MIN_WIDTH = "minWidth";
+    String MAX_WIDTH = "maxWidth";
+    String HEIGHT = "height";
+    String MIN_HEIGHT = "minHeight";
+    String MAX_HEIGHT = "maxHeight";
+    String ALIGN_ITEMS = "alignItems";
+    String ALIGN_SELF = "alignSelf";
+    String FLEX = "flex";
+    String FLEX_DIRECTION = "flexDirection";
+    String JUSTIFY_CONTENT = "justifyContent";
+    String FLEX_WRAP = "flexWrap";
+
+    String MARGIN = "margin";
+    String MARGIN_TOP = "marginTop";
+    String MARGIN_LEFT = "marginLeft";
+    String MARGIN_RIGHT = "marginRight";
+    String MARGIN_BOTTOM = "marginBottom";
+    String PADDING = "padding";
+    String PADDING_TOP = "paddingTop";
+    String PADDING_LEFT = "paddingLeft";
+    String PADDING_RIGHT = "paddingRight";
+    String PADDING_BOTTOM = "paddingBottom";
+
+    String LEFT = "left";
+    String TOP = "top";
+    String RIGHT = "right";
+    String BOTTOM = "bottom";
+
+
+    String BACKGROUND_COLOR = "backgroundColor";
+    String BACKGROUND_IMAGE = "backgroundImage";
+    String OPACITY = "opacity";
+    String BORDER_RADIUS = "borderRadius";
+    String BORDER_WIDTH = "borderWidth";
+    String BORDER_COLOR = "borderColor";
+    String BORDER_STYLE = "borderStyle";
+    String BORDER_TOP_WIDTH = "borderTopWidth";
+    String BORDER_RIGHT_WIDTH = "borderRightWidth";
+    String BORDER_BOTTOM_WIDTH = "borderBottomWidth";
+    String BORDER_LEFT_WIDTH = "borderLeftWidth";
+    String BORDER_TOP_COLOR = "borderTopColor";
+    String BORDER_RIGHT_COLOR = "borderRightColor";
+    String BORDER_BOTTOM_COLOR = "borderBottomColor";
+    String BORDER_LEFT_COLOR = "borderLeftColor";
+    String BORDER_TOP_LEFT_RADIUS = "borderTopLeftRadius";
+    String BORDER_TOP_RIGHT_RADIUS = "borderTopRightRadius";
+    String BORDER_BOTTOM_RIGHT_RADIUS = "borderBottomRightRadius";
+    String BORDER_BOTTOM_LEFT_RADIUS = "borderBottomLeftRadius";
+    String BORDER_RIGHT_STYLE = "borderRightStyle";
+    String BORDER_BOTTOM_STYLE = "borderBottomStyle";
+    String BORDER_LEFT_STYLE = "borderLeftStyle";
+    String BORDER_TOP_STYLE = "borderTopStyle";
+    String BOX_SHADOW = "boxShadow";
+    String SHADOW_QUALITY = "shadowQuality";
+
+    String POSITION = "position";
+
+    String KEEP_SCROLL_POSITION = "keepScrollPosition";
+
+    String TEXT_DECORATION = "textDecoration";
+    String TEXT_ALIGN = "textAlign";
+    String FONT_WEIGHT = "fontWeight";
+    String FONT_STYLE = "fontStyle";
+    String FONT_SIZE = "fontSize";
+    String COLOR = "color";
+    String LINES = "lines";
+    String FONT_FAMILY = "fontFamily";
+    String TEXT_OVERFLOW = "textOverflow";
+    String ELLIPSIS = "ellipsis";
+    String LINE_HEIGHT = "lineHeight";
+    String DISABLED = "disabled";
+    String VALUE = "value";
+    String IMAGE_QUALITY = "imageQuality";
+    String FILTER = "filter";
+    String QUALITY = "quality";
+    String SRC = "src";
+    String SOURCE = "source";
+    String PLACE_HOLDER = "placeHolder";
+    String RESIZE_MODE = "resizeMode";
+    String AUTO_RECYCLE = "autoBitmapRecycle";
+    String SHOW_INDICATORS = "showIndicators";
+    String AUTO_PLAY = "autoPlay";
+    String AUTOPLAY = "autoplay";
+    String CONTROLS = "controls";
+    String ZORDERTOP = "zOrderTop";
+    String SCROLL_DIRECTION = "scrollDirection";
+    String SCOPE = "scope";
+    String RECYCLE = "recycle";
+    String LOADMORERETRY = "loadmoreretry";
+    String LOADMOREOFFSET = "loadmoreoffset";
+    String RECYCLE_IMAGE = "recycleImage";
+    String LAYOUT = "layout";
+    String SPAN_OFFSETS = "spanOffsets";
+    String COLUMN_WIDTH = "columnWidth";
+    String COLUMN_COUNT = "columnCount";
+    String COLUMN_GAP = "columnGap";
+    String SHOW_SCROLLBAR = "showScrollbar";
+    String LEFT_GAP= "leftGap";
+    String RIGHT_GAP= "rightGap";
+    String OVERFLOW = "overflow";
+    String TYPE = "type";
+    String PLACEHOLDER = "placeholder";
+    String PLACEHOLDER_COLOR = "placeholderColor";
+    String AUTOFOCUS = "autofocus";
+    String SINGLELINE = "singleline";
+    String MAX_LENGTH = "maxLength";
+    String MAXLENGTH = "maxlength";
+    String ROWS = "rows";
+    String CHECKED = "checked";
+    String ANIMATING = "animating";
+    String VISIBILITY = "visibility";
+    String ITEM_COLOR = "itemColor";
+    String ITEM_SELECTED_COLOR = "itemSelectedColor";
+    String ITEM_SIZE = "itemSize";
+    String DISPLAY = "display";
+    String SHOW_LOADING = "show-loading";
+    String SUFFIX = "suffix";
+    String RESIZE = "resize";
+    String IMAGE_SHARPEN = "imageSharpen";
+    String SHARPEN = "sharpen";
+    String PREFIX = "prefix";
+    String INDEX = "index";
+    String INTERVAL = "interval";
+    String PLAY_STATUS = "playStatus";
+    String FONT_FACE = "fontFace";
+    String MAX = "max";
+    String MIN = "min";
+    String NAV_BAR_VISIBILITY = "hidden";
+    String OFFSET_X_ACCURACY = "offsetXAccuracy";
+    String OFFSET_X_RATIO = "offsetXRatio";
+    String ELEVATION = "elevation";
+    String PERSPECTIVE = "perspective";
+    String SCROLLABLE = "scrollable";
+    String DRAGGABLE = "draggable";
+    String DISTANCE_Y = "dy";
+    String PULLING_DISTANCE = "pullingDistance";
+    String VIEW_HEIGHT = "viewHeight";
+    String PREVENT_MOVE_EVENT = "preventMoveEvent";
+    String SELECTION_START = "selectionStart";
+    String SELECTION_END = "selectionEnd";
+    String OFFSET_ACCURACY = "offsetAccuracy";
+    String CONTENT_SIZE = "contentSize";
+    String CONTENT_OFFSET = "contentOffset";
+    String ISDRAGGING = "isDragging";
+    String X = "x";
+    String Y = "y";
+    String RETURN_KEY_TYPE = "returnKeyType";
+    String OFFSET = "offset";
+    String ANIMATED = "animated";
+    String STABLE = "stable";
+    String TRANSFORM = "transform";
+    String TRANSFORM_ORIGIN = "transformOrigin";
+    String KEEP_INDEX = "keepIndex";
+    String KEEP_SELECTION_INDEX = "keepSelectionIndex";
+
+    String INSERT_CELL_ANIMATION = "insertAnimation";
+    String DELETE_CELL_ANIMATION = "deleteAnimation";
+    String AUTO = "auto";
+    String NORMAL = "normal";
+    String ARIA_LABEL = "ariaLabel";
+    String ARIA_HIDDEN = "ariaHidden";
+    String ROLE = "role";
+
+    String LAYERLIMIT = "layerLimit";
+    String LAYER_LIMIT = "layer-limit";
+
+    String DIRECTION = "direction";
+    String RTL = "rtl";
+
+    String STICKY_OFFSET = "stickyOffset";
+    String HAS_FIXED_SIZE = "hasFixedSize";
+    String KEEP_POSITION_LAYOUT_DELAY = "keepPositionLayoutDelay";
+
+    String OVERFLOW_HIDDEN_HEIGHT = "overflowHiddenHeight";
+    String OVERFLOW_HIDDEN_WIDTH = "overflowHiddenWidth";
+
+    String PRIORITY  = "priority";
+
+    String STRATEGY  = "strategy";
+
+    String ALLOW_COPY_PASTE = "allowCopyPaste";
+    String INCLUDE_FONT_PADDING = "includeFontPadding";
+    String ENABLE_COPY = "enableCopy";
+
+    String PAGE_ENABLED = "pagingEnabled";
+    String PAGE_SIZE = "pageSize";
+
+
+
+    interface  Recycler{
+      String LIST_DATA = "listData";
+      String LIST_DATA_ITEM  ="alias";
+      String LIST_DATA_ITEM_INDEX = "index";
+      String LIST_DATA_TEMPLATE_SWITCH_KEY = "switch";
+      String SLOT_TEMPLATE_CASE = "case";
+      String SLOT_TEMPLATE_DEFAULT = "default";
+      String CELL_INDEX = "cellIndex";
+      String TYPE_INDEX = "typeIndex";
+    }
+
+
+    String VIF_FALSE = "ifFalse";
+    String UNDEFINED = "undefined";
+    String FLAT = "flat";
+    String RIPPLE_ENABLED = "rippleEnabled";
+
+    String SHOULD_STOP_PROPAGATION_INIT_RESULT = "shouldStopPropagationInitResult";
+    String SHOULD_STOP_PROPAGATION_INTERVAL = "shouldStopPropagationInterval";
+
+
+    String NEST_SCROLLING_ENABLED = "nestedScrollingEnabled";
+
+    String ORIENTATION  = "orientation";
+  }
+
+  public interface Value {
+
+    int DENSITY = 3;
+    int NAV_BAR_SHOWN = 0;
+    int NAV_BAR_HIDDEN = 1;
+    int AUTO = -1;
+    int COLUMN_GAP_NORMAL = 32;
+    int COLUMN_COUNT_NORMAL = 1;
+    String MULTI_COLUMN = "multi-column";
+    String GRID = "grid";
+    String STICKY = "sticky";
+    String FIXED = "fixed";
+    String LEFT = "left";
+    String RIGHT = "right";
+    String CENTER = "center";
+    String BOLD = "bold";
+    String ITALIC = "italic";
+    String ORIGINAL = "original";
+    String LOW = "low";
+    String NORMAL = "normal";
+    String HIGH = "high";
+    String VISIBLE = "visible";
+    String HIDDEN = "hidden";
+    String TEXT = "text";
+    String PASSWORD = "password";
+    String TEL = "tel";
+    String EMAIL = "email";
+    String URL = "url";
+    String DATE = "date";
+    String TIME = "time";
+    String DATETIME = "datetime";
+    String PLAY = "play";
+    String PAUSE = "pause";
+    String STOP = "stop";
+    String DIRECTION_LEFT = "left";
+    String DIRECTION_RIGHT = "right";
+    String DIRECTION_UP = "up";
+    String DIRECTION_DOWN = "down";
+    String NUMBER = "number";
+
+    String NONE = "none";
+    String DEFAULT = "default";
+
+    String HORIZONTAL = "horizontal";
+  }
+
+  public interface Event {
+
+    String CLICK = "click";
+    String APPEAR = "appear";
+    String DISAPPEAR = "disappear";
+    String LOADMORE = "loadmore";
+    String FOCUS = "focus";
+    String BLUR = "blur";
+    String INPUT = "input";
+    String VIEWAPPEAR = "viewappear";
+    String VIEWDISAPPEAR = "viewdisappear";
+    String START = "start";
+    String PAUSE = "pause";
+    String FINISH = "finish";
+    String FAIL = "fail";
+    String ERROR = "error";
+    String RECEIVEDTITLE = "receivedtitle";
+    String PAGEFINISH = "pagefinish";
+    String PAGESTART = "pagestart";
+    String ONREFRESH = "refresh";
+    String ONLOADING = "loading";
+    String ONLOAD = "load";
+    String CHANGE = "change";
+    String ONPULLING_DOWN = "pullingdown";
+    String ONPULLING_UP = "pullingup";
+    String SCROLL = "scroll";
+    String SCROLL_START = "scrollstart";
+    String SCROLL_END = "scrollend";
+    String CLICKBACKITEM = "clickbackitem";
+    String RESUME_EVENT = "WXApplicationDidBecomeActiveEvent";
+    String PAUSE_EVENT = "WXApplicationWillResignActiveEvent";
+    String RETURN = "return";
+    String KEYBOARD = "keyboard";
+
+    String UNSTICKY = "unsticky";
+    String STICKY = "sticky";
+
+    String ON_TRANSITION_END = "transitionEnd";
+
+    String LAYEROVERFLOW = "layeroverflow";
+
+    interface SLOT_LIFECYCLE {
+      String CREATE = "create";
+      String ATTACH = "attach";
+      String DETACH = "detach";
+      String DESTORY = "destroy";
+    }
+
+    String STOP_PROPAGATION = "stopPropagation";
+    String STOP_PROPAGATION_RAX = "stoppropagation";
+    String ONMESSAGE = "message";
+    String NATIVE_BACK = "nativeback";
+  }
+
+  public interface PSEUDO {
+    String ACTIVE = ":active";
+    String ENABLED = ":enabled";
+    String DISABLED = ":disabled";
+    String FOCUS = ":focus";
+  }
+
+  public interface Scheme {
+
+    String FILE = "file";
+    String HTTPS = "https";
+    String HTTP = "http";
+    String LOCAL = "local";
+    String DATA = "data";
+  }
+
+  public interface CodeCache {
+    String URL = "bundleUrl";
+    String DIGEST = "bundleDigest";
+    String PATH = "codeCachePath";
+    String BANNER_DIGEST = "digest";
+    String SAVE_PATH = "v8";
+  }
+
+  public interface TimeFunction {
+    String LINEAR = "linear";
+    String EASE_IN_OUT = "ease-in-out";
+    String EASE_IN = "ease-in";
+    String EASE_OUT = "ease-out";
+    String EASE = "ease";
+    String CUBIC_BEZIER = "cubic-bezier";
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/Destroyable.java b/android/sdk/src/main/java/org/apache/weex/common/Destroyable.java
new file mode 100644
index 0000000..8beca57
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/Destroyable.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+/**
+ * Created by sospartan on 5/20/16.
+ */
+public interface Destroyable {
+    public void destroy();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/ICheckBindingScroller.java b/android/sdk/src/main/java/org/apache/weex/common/ICheckBindingScroller.java
new file mode 100644
index 0000000..3a4ab5d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/ICheckBindingScroller.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+/**
+ * Created by zhengshihan on 2017/6/5.
+ */
+
+public interface ICheckBindingScroller {
+  boolean isNeedScroller(String ref,Object option);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/IWXBridge.java b/android/sdk/src/main/java/org/apache/weex/common/IWXBridge.java
new file mode 100755
index 0000000..01858ea
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/IWXBridge.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import org.apache.weex.bridge.ResultCallback;
+import org.apache.weex.bridge.WXJSObject;
+import org.apache.weex.bridge.WXParams;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * Bridge interface, native bridge and debug bridge both need to implement this interface
+ */
+public interface IWXBridge extends IWXObject {
+
+  int DESTROY_INSTANCE = -1;
+  int INSTANCE_RENDERING = 1;
+  int INSTANCE_RENDERING_ERROR = 0;
+
+  /**
+   * init Weex
+   *
+   * @param framework assets/main.js
+   * @return
+   */
+  int initFramework(String framework, WXParams params);
+
+
+  /**
+   * init Weex
+   *
+   * @param framework assets/main.js
+   * @return
+   */
+  int initFrameworkEnv(String framework, WXParams params, String cacheDir, boolean pieSupport);
+
+
+  /**
+   * Update InitFramework Params
+   * */
+  void updateInitFrameworkParams(String key, String value, String desc);
+
+
+  void setLogType(float type, boolean isPerf);
+
+  void refreshInstance(String instanceId, String namespace, String function, WXJSObject[] args);
+
+  /**
+   * execute javascript function
+   */
+  int execJS(String instanceId, String namespace, String function, WXJSObject[] args);
+
+  /**
+   * execute javascript function with asynchronous callback
+   */
+  void execJSWithCallback(String instanceId, String namespace, String function, WXJSObject[] args, ResultCallback callback);
+
+  int execJSService(String javascript);
+
+  /**
+   * take the heap snapshot and serialize the heap to a local file.
+   *
+   * @param filename
+   */
+  void takeHeapSnapshot(String filename);
+
+  /**
+   * createInstance
+   * @param instanceId
+   * @param namespace
+   * @param function
+   * @param args
+   * @return
+   */
+  int createInstanceContext(String instanceId, String namespace, String function, WXJSObject[] args);
+
+  /**
+   * destoryInstance
+   * @param instanceId
+   * @param namespace
+   * @param function
+   * @param args
+   * @return
+   */
+  int destoryInstance(String instanceId, String namespace, String function, WXJSObject[] args);
+
+  /**
+   * execJSOnInstance
+   * @param instanceId
+   * @param script
+   * @param type
+   * @return
+   */
+  String execJSOnInstance(String instanceId, String script, int type);
+
+  /**
+   * js call native
+   */
+  int callNative(String instanceId, byte[] tasks, String callback);
+
+
+  int callNative(String instanceId, String tasks, String callback);
+
+  void reportJSException(String instanceId, String func, String exception);
+
+  Object callNativeModule(String instanceId, String module, String method, byte[] arguments, byte[] options);
+
+  void callNativeComponent(String instanceId, String ref, String method, byte[] arguments, byte[] options);
+
+  int callUpdateFinish(String instanceId, byte[] tasks, String callback);
+
+  int callRefreshFinish(String instanceId, byte[] tasks, String callback);
+
+  void reportServerCrash(String instanceId, String crashFile);
+
+
+  int callCreateBody(String instanceId, String componentType, String ref,
+                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
+                            float[] margins, float[] paddings, float[] borders);
+
+  int callAddElement(String instanceId, String componentType, String ref, int index, String parentRef,
+                            HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
+                            float[] margins, float[] paddings, float[] borders, boolean willLayout);
+
+  int callRemoveElement(String instanceId, String ref);
+
+  int callMoveElement(String instanceId, String ref, String parentref, int index);
+
+  int callAddEvent(String instanceId, String ref, String event);
+
+  int callRemoveEvent(String instanceId, String ref, String event);
+
+  int callUpdateStyle(String instanceId, String ref,
+                             HashMap<String, Object> styles,
+                             HashMap<String, String> paddings,
+                             HashMap<String, String> margins,
+                             HashMap<String, String> borders);
+
+  int callUpdateAttrs(String instanceId, String ref,
+                      HashMap<String, String> attrs);
+
+  int callAddChildToRichtext(String instanceId, String nodeType, String ref, String parentRef, String richTextRef,
+                             HashMap<String, String> styles, HashMap<String, String> attrs);
+
+  int callRemoveChildFromRichtext(String instanceId, String ref, String parentRef, String richTextRef);
+
+  int callUpdateRichtextStyle(String instanceId, String ref, HashMap<String, String> styles, String parentRef, String richTextRef);
+
+  int callUpdateRichtextChildAttr(String instanceId, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef);
+
+  int callLayout(String instanceId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index);
+
+  int callCreateFinish(String instanceId);
+
+  int callRenderSuccess(String instanceId);
+
+  int callAppendTreeCreateFinish(String instanceId, String ref);
+
+  int callHasTransitionPros(String instanceId, String ref, HashMap<String, String> styles);
+
+  ContentBoxMeasurement getMeasurementFunc(String instanceId, long renderObjectPtr);
+
+  void bindMeasurementToRenderObject(long ptr);
+
+  void setRenderContainerWrapContent(boolean wrap, String instanceId);
+
+  long[] getFirstScreenRenderTime(String instanceId);
+
+  long[] getRenderFinishTime(String instanceId);
+
+  void setDefaultHeightAndWidthIntoRootDom(String instanceId, float defaultWidth, float defaultHeight, boolean isWidthWrapContent, boolean isHeightWrapContent);
+
+  void onInstanceClose(String instanceId);
+
+  void forceLayout(String instanceId);
+
+  boolean notifyLayout(String instanceId);
+
+  void setStyleWidth(String instanceId, String ref, float value);
+
+  void setStyleHeight(String instanceId, String ref, float value);
+
+  void setMargin(String instanceId, String ref, CSSShorthand.EDGE edge, float value);
+
+  void setPadding(String instanceId, String ref, CSSShorthand.EDGE edge, float value);
+
+  void setPosition(String instanceId, String ref, CSSShorthand.EDGE edge, float value);
+
+  void markDirty(String instanceId, String ref, boolean dirty);
+
+  void setDeviceDisplay(String instanceId, float width, float height, float scale);
+
+  void registerCoreEnv(String key, String value);
+
+  void reportNativeInitStatus(String statusCode, String errorMsg);
+
+  void setTimeoutNative(String callbackId, String time);
+
+  void setJSFrmVersion(String version);
+
+  void resetWXBridge(boolean remoteDebug);
+
+  void setInstanceRenderType(String instanceId, String renderType);
+
+  void removeInstanceRenderType(String instanceId);
+
+  void setPageArgument(String instanceId, String key, String value);
+
+  void setViewPortWidth(String instanceId,float viewPortWidth);
+
+  void reloadPageLayout(String instanceId);
+
+  void setDeviceDisplayOfPage(String instanceId, float width, float height);
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/IWXDebugConfig.java b/android/sdk/src/main/java/org/apache/weex/common/IWXDebugConfig.java
new file mode 100644
index 0000000..6d76268
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/IWXDebugConfig.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.bridge.WXDebugJsBridge;
+
+public interface IWXDebugConfig {
+
+  WXBridgeManager getWXJSManager();
+
+  WXDebugJsBridge getWXDebugJsBridge();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/IWXObject.java b/android/sdk/src/main/java/org/apache/weex/common/IWXObject.java
new file mode 100644
index 0000000..4b3ae4a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/IWXObject.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public interface IWXObject {
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/OnWXScrollListener.java b/android/sdk/src/main/java/org/apache/weex/common/OnWXScrollListener.java
new file mode 100644
index 0000000..450b8ae
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/OnWXScrollListener.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+
+public interface OnWXScrollListener {
+
+  /**
+   * The  view is not currently scrolling.
+   */
+  int IDLE = RecyclerView.SCROLL_STATE_IDLE;
+  /**
+   * The view is currently being dragged by outside input such as user touch input.
+   */
+  int DRAGGING = RecyclerView.SCROLL_STATE_DRAGGING;
+  /**
+   * The view is currently animating to a final position while not under
+   * outside control.
+   */
+  int SETTLING = RecyclerView.SCROLL_STATE_SETTLING;
+
+  /**
+   * Callback method to be invoked when the view has been scrolled. This will be
+   * called after the scroll has completed.
+   * <p>
+   * This callback will also be called if visible item range changes after a layout
+   * calculation. In that case, dx and dy will be 0.
+   *
+   */
+  void onScrolled(View view, int x, int y);
+
+  /**
+   * Callback method to be invoked when view's scroll state changes.
+   *
+   */
+  void onScrollStateChanged(View view, int x, int y, int newState);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/RenderTypes.java b/android/sdk/src/main/java/org/apache/weex/common/RenderTypes.java
new file mode 100644
index 0000000..8e3a105
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/RenderTypes.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public class RenderTypes {
+
+    public static final String RENDER_TYPE_NATIVE = "platform";
+
+    public static final String RENDER_TYPE_HERON = "heron";
+    public static final String RENDER_TYPE_HERON_URL_PARAM = "wx_heron=true";
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/TypeModuleFactory.java b/android/sdk/src/main/java/org/apache/weex/common/TypeModuleFactory.java
new file mode 100644
index 0000000..f31ef93
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/TypeModuleFactory.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.Invoker;
+import org.apache.weex.bridge.MethodInvoker;
+import org.apache.weex.bridge.ModuleFactory;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Use class
+ * Created by sospartan on 6/17/16.
+ */
+public class TypeModuleFactory<T extends WXModule> implements ModuleFactory<T> {
+  public static final String TAG = "TypeModuleFactory";
+  Class<T> mClazz;
+  Map<String, Invoker> mMethodMap;
+
+  public TypeModuleFactory(Class<T> clz) {
+    mClazz = clz;
+  }
+
+  private void generateMethodMap() {
+    if(WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d(TAG, "extractMethodNames:" + mClazz.getSimpleName());
+    }
+    HashMap<String, Invoker> methodMap = new HashMap<>();
+    try {
+      for (Method method : mClazz.getMethods()) {
+        // iterates all the annotations available in the method
+        for (Annotation anno : method.getDeclaredAnnotations()) {
+          if (anno != null) {
+            if(anno instanceof JSMethod) {
+              JSMethod methodAnnotation = (JSMethod) anno;
+              String name = JSMethod.NOT_SET.equals(methodAnnotation.alias())? method.getName():methodAnnotation.alias();
+              methodMap.put(name, new MethodInvoker(method, methodAnnotation.uiThread()));
+              break;
+            }else if(anno instanceof WXModuleAnno) {
+              WXModuleAnno methodAnnotation = (WXModuleAnno)anno;
+              methodMap.put(method.getName(), new MethodInvoker(method,methodAnnotation.runOnUIThread()));
+              break;
+            }
+          }
+        }
+      }
+    } catch (Throwable e) {
+      WXLogUtils.e("[WXModuleManager] extractMethodNames:", e);
+    }
+    mMethodMap = methodMap;
+  }
+
+
+  @Override
+  public T buildInstance() throws IllegalAccessException, InstantiationException {
+    return mClazz.newInstance();
+  }
+
+  @Override
+  public String[] getMethods() {
+    if (mMethodMap == null) {
+      generateMethodMap();
+    }
+    Set<String> keys = mMethodMap.keySet();
+    return keys.toArray(new String[keys.size()]);
+  }
+
+  @Override
+  public Invoker getMethodInvoker(String name) {
+    if (mMethodMap == null) {
+      generateMethodMap();
+    }
+    return mMethodMap.get(name);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXCompatModule.java b/android/sdk/src/main/java/org/apache/weex/common/WXCompatModule.java
new file mode 100644
index 0000000..1cbf4b0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXCompatModule.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.v4.content.LocalBroadcastManager;
+
+import org.apache.weex.WXEnvironment;
+
+/**
+ * Created by lixinke on 16/10/10.
+ */
+
+public abstract class WXCompatModule extends WXModule implements Destroyable {
+
+  private ModuleReceive mModuleReceive;
+
+  public WXCompatModule() {
+    mModuleReceive = new ModuleReceive(this);
+    LocalBroadcastManager.getInstance(WXEnvironment.getApplication())
+        .registerReceiver(mModuleReceive, new IntentFilter(WXModule.ACTION_ACTIVITY_RESULT));
+    LocalBroadcastManager.getInstance(WXEnvironment.getApplication())
+        .registerReceiver(mModuleReceive, new IntentFilter(WXModule.ACTION_REQUEST_PERMISSIONS_RESULT));
+  }
+
+  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+  }
+
+  public void onActivityResult(int requestCode, int resultCode, Intent data) {
+  }
+
+  @Override
+  public void destroy() {
+    LocalBroadcastManager.getInstance(WXEnvironment.getApplication())
+        .unregisterReceiver(mModuleReceive);
+  }
+
+  static class ModuleReceive extends BroadcastReceiver {
+
+    private WXCompatModule mWXCompatModule;
+
+    ModuleReceive(WXCompatModule module) {
+      mWXCompatModule = module;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+      String action = intent.getAction();
+      switch (action) {
+        case WXModule.ACTION_ACTIVITY_RESULT:
+          int requestCode = intent.getIntExtra(WXModule.REQUEST_CODE, -1);
+          int resultCode = intent.getIntExtra(WXModule.RESULT_CODE, Activity.RESULT_OK);
+          mWXCompatModule.onActivityResult(requestCode, resultCode, intent);
+          break;
+        case WXModule.ACTION_REQUEST_PERMISSIONS_RESULT:
+          requestCode = intent.getIntExtra(WXModule.REQUEST_CODE, -1);
+          String[] permissions = intent.getStringArrayExtra(WXModule.PERMISSIONS);
+          int[] grantResults = intent.getIntArrayExtra(WXModule.GRANT_RESULTS);
+          mWXCompatModule.onRequestPermissionsResult(requestCode, permissions, grantResults);
+          break;
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXConfig.java b/android/sdk/src/main/java/org/apache/weex/common/WXConfig.java
new file mode 100644
index 0000000..88fd5f1
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXConfig.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public interface WXConfig {
+
+  String os = "os";
+  String osName = "osName";
+  String appVersion="appVersion";
+  String cacheDir = "cacheDir";
+  String devId="devId";
+  String sysVersion="sysVersion";
+  String sysModel="sysModel";
+  String weexVersion="weexVersion";
+  String appName="appName";
+  String appGroup="appGroup";
+  String externalUserAgent="externalUserAgent";
+  String logLevel="logLevel";
+  String scale = "scale";
+  String layoutDirection = "layoutDirection";
+  String debugMode = "debugMode";
+  String androidStatusBarHeight = "androidStatusBarHeight";
+  String deviceHeight = "deviceHeight";
+  String deviceWidth = "deviceWidth";
+
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXErrorCode.java b/android/sdk/src/main/java/org/apache/weex/common/WXErrorCode.java
new file mode 100644
index 0000000..8b886a2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXErrorCode.java
@@ -0,0 +1,344 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+
+public enum WXErrorCode {
+
+
+  /*
+   * environment
+   **/
+  /**
+   * Failure for load so library
+   */
+  WX_ERR_LOAD_SO("-2001", "load so error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * Failure for load JSLib
+   */
+  WX_ERR_LOAD_JSLIB("-2002", "unzip JSLib error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * So library corrupted
+   */
+  WX_ERR_BAD_SO("-2003", "so size error, to reload apk so",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * Failure for extract and copy so from apk
+   */
+  WX_ERR_COPY_FROM_APK("-2007", "system load so error,copy from APK also error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * jsBridge
+   **/
+  /**
+   * Error for JavaScript function parameter
+   */
+  WX_ERR_JSFUNC_PARAM("-2009", "JS params error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * Error for parsing JSON object
+   */
+  WX_ERR_JSON_OBJECT("-2008", "transform JSON->OBJ  error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * Failure for invoking JavaScript function
+   */
+  WX_ERR_INVOKE_NATIVE("-2012", "Native-> Call ->JS  error!",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * Failure for executing JavaScript function.
+   */
+  WX_ERR_JS_EXECUTE("-2013", "JavaScript execute error!",ErrorType.JS_ERROR,ErrorGroup.JS),
+
+
+  /*
+   * domModule
+   **/
+  WX_SUCCESS("0", "successful",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for createBody
+   */
+  WX_ERR_DOM_CREATEBODY("-2100", "createBody error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for updateAttrs
+   */
+  WX_ERR_DOM_UPDATEATTRS("-2101", "updateAttrs error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for updateAttr
+   */
+  WX_ERR_DOM_UPDATESTYLE("-2102", "updateStyle error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for addElement
+   */
+  WX_ERR_DOM_ADDELEMENT("-2103", "addElement error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for removeElement
+   */
+  WX_ERR_DOM_REMOVEELEMENT("-2104", "removeElement error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for moveElement
+   */
+  WX_ERR_DOM_MOVEELEMENT("-2105", "moveElement error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for addEvent
+   */
+  WX_ERR_DOM_ADDEVENT("-2106", "addEvent error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for removeEvent
+   */
+  WX_ERR_DOM_REMOVEEVENT("-2107", "removeEvent error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for invoking createFinish
+   */
+  WX_ERROR_DOM_CREATEFINISH("-2108", "createFinish error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for invoking refreshFinish
+   */
+  WX_ERROR_DOM_REFRESHFINISH("-2109", "refreshFinish error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Failure for scrollToElement
+   */
+  WX_ERR_DOM_SCROLLTO("-2110", "scrollToElement",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   *
+   */
+  WX_ERR_RELOAD_PAGE("-2111", "reloadPage",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_RELOAD_PAGE_EXCEED_LIMIT("-2114", "RELOAD_PAGE_EXCEED_LIMIT",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERROR_WHITE_SCREEN("-2116", "WHITE_SCREEN",ErrorType.RENDER_ERROR,ErrorGroup.JS),
+  WHITE_SCREEN_RESPONSE_TIMEOUT("-2117", "WHITE_SCREEN_RESPONSE_TIMEOUT",ErrorType.RENDER_ERROR,ErrorGroup.JS),
+  WHITE_SCREEN_REBOOT_EXCEED_LIMIT("-2118", "WHITE_SCREEN_REBOOT_EXCEED_LIMIT",ErrorType.RENDER_ERROR,ErrorGroup.JS),
+
+  /**
+   *
+   */
+  WX_ERR_JSC_CRASH("-2112", "weexjscCrash",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   *dom actions invalid for native
+   */
+  WX_ERR_FIRST_DOM_ACTION_EXCEPTION("-2113", "dom action is invalid ",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * JS Bundle download error
+   */
+
+  WX_ERR_JSDOWNLOAD_START("-2201", "js bundle download start",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_JSBUNDLE_DOWNLOAD("-2299", "js bundle download err",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_JSBUNDLE_EMPTY("-2203", "js bundle empty",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_JSDOWNLOAD_END("-2299", "js bundle download end",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  // for js framework
+  WX_JS_FRAMEWORK_INIT_SUCCESS("-1000", "js framework success",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_JS_FRAMEWORK_REINIT_SUCCESS("-1001", "js framework reinit success",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * JS Framework run error
+   */
+  WX_ERR_JS_FRAMEWORK("-1002", "js framework error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_JS_REINIT_FRAMEWORK("-1003", "js reinit framework error",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * Single progress init error
+   */
+  WX_ERR_SINGLE_PROCESS_DLOPEN_FILE_NOT_EXIST("-1004", "so file does not exist",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_SINGLE_PROCESS_DLOPEN_FLAIED("-1005", "dlopen so file failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_SINGLE_PROCESS_DLSYM_FAILED("-1006", "find function from so file failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERR_SINGLE_PROCESS_JS_FRAMEWORK("-1007", "js framework  init singleProcess failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_JS_FRAMEWORK_INIT_MULPROCESS_FAILED("-1008", "js framework init multiProcess failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_JS_FRAMEWORK_REINIT_MULPROCESS_FAILED("-1009", "js framework reinit multiProcess failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_JS_FRAMEWORK_INIT_FAILED("-1010", "js framework init failed",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_JS_FRAMEWORK_INIT_SINGLE_PROCESS_SUCCESS("-1011", "js framework init success in single process",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_JS_FRAMEWORK_INIT_FAILED_PARAMS_NULL("-1012", "js framework init failed due to params null",ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_JS_FRAMEWORK_INIT_FAILED_FIND_ICU_TIMEOUT("-1013", "find icu failed",ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+
+  /**
+   * WX Key Exception Commit RT SDK Init
+   */
+  WX_KEY_EXCEPTION_SDK_INIT("-9000", "[WX_KEY_EXCEPTION_SDK_INIT]",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT("-9001", "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for android cpu is x86",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_SDK_INIT_TABLE_NOT_SUPPORT("-9002", "[WX_KEY_EXCEPTION_SDK_INIT_TABLE_NOT_SUPPORT] for device isTabletDevice",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_SDK_INIT_JSFM_INIT_FAILED("-9003", "[WX_KEY_EXCEPTION_SDK_INIT_JSFM_INIT_FAILED] for jsfm init failed|detail error is:",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * WX Key Exception Commit RT Register
+   */
+  WX_KEY_EXCEPTION_INVOKE_BRIDGE("-9100", "[WX_KEY_EXCEPTION_INVOKE_BRIDGE]",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED("-9101", "[WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE("-9102", "[WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES("-9103", "[WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT("-9104", "[WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT] details",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+  /**
+   * WX Key Exception Commit Bundle Js Download
+   */
+  WX_KEY_EXCEPTION_JS_DOWNLOAD("-9200", "[WX_KEY_EXCEPTION_JS_DOWNLOAD]|",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED("-9201", "[WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED] | details",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * WX Key Exception Commit RT JsBridge eg. js excute runtime error
+   */
+  WX_KEY_EXCEPTION_WXBRIDGE("-9400", "[js excute runtime error] detail js stack -> ",ErrorType.JS_ERROR,ErrorGroup.JS),
+  WX_KEY_EXCEPTION_WXBRIDGE_EXCEPTION("-9401", "[js excute runtime error] detail js stack -> ",ErrorType.JS_ERROR,ErrorGroup.JS),
+
+  /**
+   * renderErrorCode
+   */
+  WX_RENDER_ERR_JS_CREATE_INSTANCE("-9600", "white screen cause create instance failed,check js stack ->",ErrorType.RENDER_ERROR,ErrorGroup.JS),
+  WX_RENDER_ERR_JS_CREATE_INSTANCE_CONTEXT("-9700", "white screen cause create instanceContext failed,check js stack ->",ErrorType.RENDER_ERROR,ErrorGroup.JS),
+  WX_RENDER_ERR_LAYER_OVERFLOW("-9602", "WX_RENDER_ERR_LAYER_OVERFLOW", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_RENDER_ERR_NULL_KEY("-9603", "WX_RENDER_ERR_NULL_KEY", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_RENDER_ERR_NATIVE_RUNTIME("-9604", "WX_RENDER_ERR for js error", ErrorType.RENDER_ERROR, ErrorGroup.NATIVE),
+  WX_RENDER_ERR_COMPONENT_NOT_REGISTER("-9605", "WX_RENDER_ERR_COMPONENT_NOT_REGISTER", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_RENDER_ERR_COMPONENT_ATTR_KEY("-9606", "The key passed to Component.updateAttr() is not string", ErrorType.NATIVE_ERROR, ErrorGroup.JS),
+  WX_RENDER_ERR_BRIDGE_ARG_NULL("-9610", "WX_RENDER_ERR_BRIDGE_ARG_NULL", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_RENDER_ERR_CONTAINER_TYPE("-9611", "WX_RENDER_ERR_CONTAINER_TYPE", ErrorType.JS_ERROR,ErrorGroup.JS),
+  WX_RENDER_ERR_TRANSITION("-9616", "WX_RENDER_ERR_TRANSITION", ErrorType.JS_ERROR, ErrorGroup.JS),
+  WX_RENDER_ERR_INSTANCE_ID_NULL("-9618", "WX_RENDER_ERR_INSTANCE_ID_NULL", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_RENDER_ERR_LIST_INVALID_COLUMN_COUNT("-9619", "WX_RENDER_ERR_LIST_INVALID_COLUMNJ_CONUNT", ErrorType.JS_ERROR, ErrorGroup.JS),
+  WX_RENDER_ERR_TEXTURE_SETBACKGROUND("-9620", "WX_RENDER_ERR_TEXTURE_SETBACKGROUND", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_RENDER_WAR_GPU_LIMIT_LAYOUT("-9621", "WX_RENDER_WAR_GPU_LIMIT_LAYOUT", ErrorType.JS_ERROR,ErrorGroup.JS),
+
+  WX_KEY_EXCEPTION_HERON("Heron_-9900", "Error of Heron engine: ", ErrorType.NATIVE_ERROR, ErrorGroup.NATIVE),
+  WX_KEY_EXCEPTION_HERON_RENDER("Heron_-9901", "Render error of Heron engine: ", ErrorType.RENDER_ERROR, ErrorGroup.NATIVE),
+
+  WX_KEY_EXCEPTION_NO_BUNDLE_TYPE("-9801", "Fatal Error : No bundle type in js bundle head, cause white screen or memory leak!!", ErrorType.JS_ERROR, ErrorGroup.JS),
+  /**
+   * degrade code.
+   */
+  WX_DEGRAD_ERR("-1000", "degradeToH5|Weex DegradPassivity ->",ErrorType.DEGRAD_ERROR,ErrorGroup.JS),
+
+  /**
+   * degrade for instance create failed, once this case occured,detail js stack and other specific
+   * cause need track into errmsg.
+   */
+  WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED("-1001", "degradeToH5|createInstance fail|wx_create_instance_error",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * degrade for network failed download js bundle.once this case occured,network requist response header
+   * and statuscode need track into errmsg.
+   */
+  WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED("-1002", "|wx_network_error|js bundle download failed",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * degrade for network failed for bundlejs is unbroken , once this case occured,network requist response header
+   * and statuscode need track into errmsg.
+   */
+  WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED("-1003", "degradeToH5|wx_network_error|js bundle content-length check failed",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * degrade for Response header Content-Type is null or not "application/javascript".
+   * once this case occured,network requist response header and statuscode need track into errmsg.
+   */
+  WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR("-1004", "degradeToH5|wx_user_intercept_error |Content-Type is not application/javascript, " +
+          "Weex render template must be javascript, please check your request!",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
+
+  /**
+   * degrade for other reason. such as white screen which block error for some unknown reason.
+   * once this case occured,detail msg need track.
+   */
+  WX_DEGRAD_ERR_OTHER_CAUSE_DEGRADTOH5("-1005", "degradeToH5|for other reason|",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE),
+
+
+  WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED_JS("-1006", "degradeToH5|createInstance fail|wx_create_instance_error",ErrorType.DEGRAD_ERROR,ErrorGroup.JS),
+
+  WX_DEGRAD_EAGLE_RENDER_ERROR ("Eagle_-1007", "degradeToH5|eagleRenderErr", ErrorType.DEGRAD_ERROR, ErrorGroup.NATIVE),
+
+  WX_ERR_HASH_MAP_TMP("-10010", "WX_ERR_HASH_MAP_TMP",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE),
+
+  WX_ERROR_MOVE_RENDER_OBJECT_OUT_OF_BOUNDS("-2120", "Index out of bounds when move element",
+      ErrorType.NATIVE_ERROR, ErrorGroup.JS),
+
+  /**
+   * TEST
+   */
+
+  WX_ERR_TEST("test", "test",ErrorType.NATIVE_ERROR,ErrorGroup.NATIVE);
+
+  private String errorCode;
+  private String errorMsg;
+  private String appendMsg="";
+  private String args;
+  private ErrorType mErrorType;
+  private ErrorGroup mErrorGroup;
+
+  WXErrorCode(String errorCode, String errorMsg,ErrorType errorType,ErrorGroup errorGroup) {
+    this.errorCode = errorCode;
+    this.errorMsg = errorMsg;
+    this.mErrorType = errorType;
+    this.mErrorGroup = errorGroup;
+  }
+
+  public void appendErrMsg(String err) {
+    appendMsg=err;
+  }
+
+  public String getErrorCode() {
+    return this.errorCode;
+  }
+
+  public String getErrorMsg() {
+    StringBuilder builder=new StringBuilder(errorMsg);
+    builder.append(appendMsg);
+    return builder.toString();
+  }
+
+  public ErrorType getErrorType() {
+    return mErrorType;
+  }
+
+  public ErrorGroup getErrorGroup() {
+    return mErrorGroup;
+  }
+
+  public String getArgs() {
+    return args;
+  }
+
+  public void setArgs(String args) {
+    this.args = args;
+  }
+
+  public enum ErrorType{
+    JS_ERROR,
+    NATIVE_ERROR,
+    RENDER_ERROR,
+    DEGRAD_ERROR,
+    DOWN_LOAD_ERROR
+  }
+
+  public enum ErrorGroup{
+    JS,
+    NATIVE
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXException.java b/android/sdk/src/main/java/org/apache/weex/common/WXException.java
new file mode 100644
index 0000000..4afb5e7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXException.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public class WXException extends Exception {
+
+  private static final long serialVersionUID = 7265837506862157379L;
+
+  public WXException(String msg) {
+    super(msg);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXImageSharpen.java b/android/sdk/src/main/java/org/apache/weex/common/WXImageSharpen.java
new file mode 100644
index 0000000..6904ce6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXImageSharpen.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public enum WXImageSharpen {
+  UNSHARPEN,
+  SHARPEN
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXImageStrategy.java b/android/sdk/src/main/java/org/apache/weex/common/WXImageStrategy.java
new file mode 100644
index 0000000..e32e370
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXImageStrategy.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import android.widget.ImageView;
+
+import org.apache.weex.WXSDKInstance;
+
+import java.util.Map;
+
+public class WXImageStrategy {
+
+
+  /**
+   * <strong>Never!</strong>
+   * <strong>Never!</strong>
+   * <strong>Never!</strong>
+   * Never use this flag, ImageView has done all the job of clipping!
+   * There is no method to read this flag any more.
+   * This field will be removed when it's appropriate.
+   */
+  @Deprecated
+  public boolean isClipping;
+
+  /**
+   * Whether to sharp the image. The default is false.
+   */
+  public boolean isSharpen;
+
+  /**
+   * The blur radius of the image. 0 means no blur.
+   * */
+  public int blurRadius;
+
+  public String placeHolder;
+
+  /**
+   * running weex instanceId
+   * @see WXSDKInstance#mInstanceId
+   */
+  public String instanceId;
+
+  public WXImageStrategy()
+  {
+
+  }
+
+  public WXImageStrategy(String instanceId)
+  {
+    this.instanceId = instanceId;
+  }
+
+
+  public ImageListener getImageListener() {
+    return imageListener;
+  }
+
+  public void setImageListener(ImageListener imageListener) {
+    this.imageListener = imageListener;
+  }
+
+  ImageListener imageListener;
+
+  public interface ImageListener{
+    public void onImageFinish(String url,ImageView imageView,boolean  result,Map extra);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXInstanceWrap.java b/android/sdk/src/main/java/org/apache/weex/common/WXInstanceWrap.java
new file mode 100644
index 0000000..e51fe02
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXInstanceWrap.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.JSMethod;
+
+/**
+ * Report template error.
+ */
+public class WXInstanceWrap extends WXModule {
+
+  @JSMethod
+  public void error(String type, String code, String info) {
+    if (mWXSDKInstance != null) {
+      WXSDKInstance root = mWXSDKInstance;
+      if(info != null && info.contains("downgrade_to_root")){
+        while (root.getParentInstance() != null){
+          root = root.getParentInstance();
+        }
+      }
+      root.onRenderError(type + "|" + code, info);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXJSBridgeMsgType.java b/android/sdk/src/main/java/org/apache/weex/common/WXJSBridgeMsgType.java
new file mode 100644
index 0000000..f2e3307
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXJSBridgeMsgType.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public class WXJSBridgeMsgType {
+
+  public static final int SET_TIMEOUT = 0x01;
+  public static final int NATIVE_CALL = 0x02;
+  public static final int FIRE_EVENT = 0x03;
+  public static final int CALLBACK = 0x04;
+  public static final int CALL_JS = 0x05;
+  public static final int CALL_JS_BATCH = 0x06;
+  public static final int INIT_FRAMEWORK = 0x07;
+  public static final int REGISTER_COMPONENTS = 0x08;
+  public static final int REGISTER_MODULES = 0x09;
+  public static final int REFRESH_INSTANCE = 0x0a;
+  public static final int MODULE_TIMEOUT = 0x0b;
+  public static final int MODULE_INTERVAL = 0x0c;
+  public static final int TAKE_HEAP_SNAPSHOT = 0x0d;
+
+  public static final int RELOAD_PAGE_NATIVE = 0x0e;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXJSEngineListener.java b/android/sdk/src/main/java/org/apache/weex/common/WXJSEngineListener.java
new file mode 100644
index 0000000..8d1b358
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXJSEngineListener.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public interface WXJSEngineListener {
+
+  void createInstanceSuccess(String instanceId);
+
+  void destroyInstanceSuccess(String instanceId);
+
+  void createInstanceFailed(String instanceId);
+
+  void destroyInstanceFailed(String instanceId);
+
+  void fireEvent(boolean success, String instanceId, String ref, String type);
+
+  void callback(boolean success, String instanceId, String funcId, String data);
+
+  void initFramework(boolean success, String version, double jslibSize);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXJSExceptionInfo.java b/android/sdk/src/main/java/org/apache/weex/common/WXJSExceptionInfo.java
new file mode 100644
index 0000000..9b627c3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXJSExceptionInfo.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+
+import org.apache.weex.WXEnvironment;
+
+import java.util.Map;
+
+public class WXJSExceptionInfo {
+
+  /**
+   * instance id
+   */
+  private String mInstanceId;
+  /**
+   * The URL where the exception occurred
+   */
+  private String mBundleUrl;
+  /**
+   * error code
+   */
+  private WXErrorCode mErrCode;
+  /**
+   * The function name of the exception
+   */
+  private String mFunction;
+  /**
+   * Exception details
+   */
+  private String mException;
+
+  /**
+   * Extended field
+   */
+  private Map<String,String> mExtParams;
+
+  /**
+   * weex sdk version
+   */
+  private String mWeexVersion = WXEnvironment.WXSDK_VERSION;
+
+  public long time;
+
+  /**
+   * js framework verison
+   */
+  private String mJsFrameworkVersion = WXEnvironment.JS_LIB_SDK_VERSION;
+
+  public WXJSExceptionInfo(String instanceId, String bundleUrl, WXErrorCode errCode, String function, String exception, Map<String,String> extParams) {
+    this.mInstanceId = instanceId;
+    this.mBundleUrl = bundleUrl;
+    this.mErrCode = errCode;
+    this.mFunction = function;
+    this.mException = exception;
+    this.mExtParams = extParams;
+    this.time = System.currentTimeMillis();
+  }
+
+  public String getInstanceId() {
+    return mInstanceId;
+  }
+
+  public void setInstanceId(String instanceId) {
+    mInstanceId = instanceId;
+  }
+
+  public String getBundleUrl() {
+    return mBundleUrl;
+  }
+
+  public void setBundleUrl(String bundleUrl) {
+    mBundleUrl = bundleUrl;
+  }
+
+  public WXErrorCode getErrCode() {
+    return mErrCode;
+  }
+
+  public void setErrCode(WXErrorCode errCode) {
+    mErrCode = errCode;
+  }
+
+  public String getFunction() {
+    return mFunction;
+  }
+
+  public void setFunction(String function) {
+    mFunction = function;
+  }
+
+  public String getException() {
+    return mException;
+  }
+
+  public void setException(String exception) {
+    mException = exception;
+  }
+
+  public Map<String, String> getExtParams() {
+    return mExtParams;
+  }
+
+  public void setExtParams(Map<String, String> extParams) {
+    mExtParams = extParams;
+  }
+
+  public String getWeexVersion() {
+    return mWeexVersion;
+  }
+
+
+  public String getJsFrameworkVersion() {
+    return mJsFrameworkVersion;
+  }
+
+
+  @Override
+  public String toString() {
+    return new StringBuilder()
+        .append(" errCode:").append(null == mErrCode?"unSetErrorCode":mErrCode.getErrorCode())
+        .append(",function:").append(null == mFunction?"unSetFuncName":mFunction)
+        .append(",exception:").append(null == mException?"unSetException":mException)
+        .toString();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXJSService.java b/android/sdk/src/main/java/org/apache/weex/common/WXJSService.java
new file mode 100644
index 0000000..bd2d347
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXJSService.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class WXJSService implements IWXObject {
+    private String name;
+    private String script;
+    private Map<String, Object> options = new HashMap<>();
+
+    public String getName() { return name; }
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getScript() { return script; }
+    public void setScript(String script) {
+        this.script = script;
+    }
+
+    public Map<String, Object> getOptions() { return options; }
+    public void setOptions(Map<String, Object> options) {
+        this.options = options;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXModule.java b/android/sdk/src/main/java/org/apache/weex/common/WXModule.java
new file mode 100644
index 0000000..4086a02
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXModule.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import android.content.Intent;
+import android.text.TextUtils;
+import android.view.Menu;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * All modules must extend this class
+ */
+public abstract class WXModule implements IWXObject {
+
+  public static final String ACTION_ACTIVITY_RESULT = "actionActivityResult";
+  public static final String ACTION_REQUEST_PERMISSIONS_RESULT = "actionRequestPermissionsResult";
+  public static final String REQUEST_CODE = "requestCode";
+  public static final String RESULT_CODE = "resultCode";
+  public static final String PERMISSIONS = "permissions";
+  public static final String GRANT_RESULTS = "grantResults";
+
+
+  public WXSDKInstance mWXSDKInstance;
+  private String mModuleName;
+
+
+  protected final WXComponent findComponent(String ref){
+    if(mWXSDKInstance != null && ref != null){
+      return WXSDKManager.getInstance()
+          .getWXRenderManager()
+          .getWXComponent(mWXSDKInstance.getInstanceId(), ref);
+    }
+    return null;
+  }
+
+  /** hook the Activity life cycle to Instance module**/
+  public void onActivityResult(int requestCode, int resultCode, Intent data){}
+
+  public void onActivityCreate(){}
+
+  public void onActivityStart(){}
+
+  public void onActivityPause(){}
+
+  public void onActivityResume(){}
+
+  public void onActivityStop(){}
+
+  public void onActivityDestroy(){}
+
+  public boolean onActivityBack() {return false;}
+
+  public boolean onCreateOptionsMenu(Menu menu){return false;}
+
+  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {}
+
+    /** end **/
+
+  private Map<String, List<String>> mEvents = new HashMap<>();
+  private Map<String, Boolean> mKeepAlives = new HashMap<>();
+
+
+
+  @JSMethod
+  public void addEventListener(String eventName, String callback, Map<String, Object> options) {
+    if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) {
+      return;
+    }
+    boolean isOnce = false;
+    if (options != null && options.size() > 0 && options.containsKey("once")) {
+      Object temp = options.get("once");
+      if (WXUtils.getBoolean(temp,false)) {
+        isOnce = true;
+      }
+    }
+    mKeepAlives.put(callback, isOnce);
+    if(mEvents.get(eventName)==null){
+      mEvents.put(eventName,new ArrayList<String>());
+    }
+    mEvents.get(eventName).add(callback);
+  }
+
+  @JSMethod
+  public void removeAllEventListeners(String eventName) {
+    if (mEvents.containsKey(eventName)) {
+      List<String> callbacks = mEvents.remove(eventName);
+      for(String callback:callbacks){
+        mKeepAlives.remove(callback);
+      }
+    }
+  }
+
+  /**
+   * Check whether the EventName has been registered
+   */
+  public List<String> getEventCallbacks(String eventName) {
+    return mEvents.get(eventName);
+  }
+
+  public boolean isOnce(String callback){
+    return mKeepAlives.get(callback);
+  }
+
+  public String getModuleName() {
+    return mModuleName;
+  }
+
+  public void setModuleName(String moduleName) {
+    mModuleName = moduleName;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXModuleAnno.java b/android/sdk/src/main/java/org/apache/weex/common/WXModuleAnno.java
new file mode 100644
index 0000000..038771c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXModuleAnno.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import org.apache.weex.annotation.JSMethod;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Use {@link JSMethod} instead. **/
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Deprecated
+public @interface WXModuleAnno {
+
+  @Deprecated
+  boolean moduleMethod() default true;
+
+  boolean runOnUIThread() default true;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXPerformance.java b/android/sdk/src/main/java/org/apache/weex/common/WXPerformance.java
new file mode 100644
index 0000000..7024086
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXPerformance.java
@@ -0,0 +1,569 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import android.support.annotation.RestrictTo;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.apache.weex.bridge.WXBridgeManager;
+
+@Deprecated
+public class WXPerformance {
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public enum Dimension {
+    JSLibVersion,
+    WXSDKVersion,
+    pageName,
+    spm,
+    scheme,
+    cacheType,
+    requestType,
+    networkType,
+    connectionType,
+    zcacheInfo,
+    wxContainerName,
+    wxInstanceType,
+    wxParentPage,
+    wxdim1,
+    wxdim2,
+    wxdim3,
+    wxdim4,
+    wxdim5,
+    bizType,
+    templateUrl,
+    useScroller
+  }
+
+  public enum Measure {
+    /**
+     * range : [min,max)
+     */
+    JSLibSize(0D, Double.MAX_VALUE),
+    //normal 300ms.. first install apk 30s ?
+    JSLibInitTime(0D, 80000D),
+    SDKInitTime(0D, 120000D),
+    SDKInitInvokeTime(0D, 5000D),
+    SDKInitExecuteTime(0D, 5000D),
+    JSTemplateSize(0D, 5000D),
+    pureNetworkTime(0D, 15000D),
+    networkTime(0D, 15000D),
+    fsCreateInstanceTime(0D, 3000D),
+    fsCallJsTotalTime(0D, 5000D),
+    fsCallJsTotalNum(0D, Double.MAX_VALUE),
+    fsCallNativeTotalTime(0D, 5000D),
+    fsCallNativeTotalNum(0D, Double.MAX_VALUE),
+    fsCallEventTotalNum(0D, Double.MAX_VALUE),
+    fsComponentCount(0D,100000D),
+    fsComponentCreateTime(0D,Double.MAX_VALUE),
+    fsRenderTime(0D, 5000D),
+    fsRequestNum(0D, 100D),
+    callCreateFinishTime(0D, 10000D),
+    cellExceedNum(0D, Double.MAX_VALUE),
+    communicateTotalTime(0D, 5000D),
+    maxDeepViewLayer(0D, Double.MAX_VALUE),
+    maxDeepVDomLayer(0D, Double.MAX_VALUE),
+    componentCount(0D, 1000000),
+    componentCreateTime(0D,Double.MAX_VALUE),
+    avgFps(0D, 61D),
+    timerCount(0D, Double.MAX_VALUE),
+
+    MaxImproveMemory(0D, Double.MAX_VALUE),
+    BackImproveMemory(0D, Double.MAX_VALUE),
+    PushImproveMemory(0D, Double.MAX_VALUE),
+    measureTime1(0D, Double.MAX_VALUE),
+    measureTime2(0D, Double.MAX_VALUE),
+    measureTime3(0D, Double.MAX_VALUE),
+    measureTime4(0D, Double.MAX_VALUE),
+    measureTime5(0D, Double.MAX_VALUE),
+
+    callBridgeTime(0D, Double.MAX_VALUE),
+    cssLayoutTime(0D, Double.MAX_VALUE),
+    parseJsonTime(0D, Double.MAX_VALUE),
+
+    communicateTime(0D, 5000D),
+    screenRenderTime(0D, 5000D),
+    totalTime(0D, 5000D),
+    localReadTime(0D, 5000D),
+    templateLoadTime(0D, 5000D),
+    packageSpendTime(0D, 5000D),
+    syncTaskTime(0D, 5000D),
+    actualNetworkTime(0D, 5000D),
+    firstScreenJSFExecuteTime(0D, 5000D),
+    //..
+
+    fluency(0D, 101D),
+    imgSizeCount(0D, 2000D),
+    interactionTime(0D,10000D),
+    interactionViewAddCount(0D, Double.MAX_VALUE),
+    interactionViewAddLimitCount(0D, Double.MAX_VALUE),
+    newFsRenderTime(0D, 10000D);
+
+    private double mMinRange, mMaxRange;
+
+    Measure(double min, double max) {
+      this.mMinRange = min;
+      this.mMaxRange = max;
+    }
+
+    public double getMinRange() {
+      return mMinRange;
+    }
+
+    public double getMaxRange() {
+      return mMaxRange;
+    }
+  }
+
+  public static final String DEFAULT = "default";
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+  public static final String CACHE_TYPE = "cacheType";
+
+  public static final int VIEW_LIMIT_HEIGHT = WXViewUtils.getScreenHeight() /3*2;
+  public static final int VIEW_LIMIT_WIDTH = WXViewUtils.getScreenWidth() /3*2;
+  public static boolean TRACE_DATA = WXEnvironment.isApkDebugable();
+
+  /**
+   * No longer needed.
+   */
+  @Deprecated
+  public String bizType = "weex";
+
+  /**
+   * Use {@link #pageName} instead.
+   */
+  @Deprecated
+  public String templateUrl;
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+  public String cacheType = "none";
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public long renderTimeOrigin;
+
+  public long renderUnixTimeOrigin;
+
+  public long fsRenderTime;
+
+  public long callCreateFinishTime;
+
+  public long interactionTime;
+
+  public long interactionRealUnixTime;
+
+  public int interactionViewAddCount;
+
+  public int interactionViewAddLimitCount;
+
+  public long newFsRenderTime;
+
+  public int localInteractionViewAddCount;
+
+  /**
+   * Time used for
+   * {@link WXBridgeManager#createInstance(String, String, Map, String)}
+   */
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public long callCreateInstanceTime;
+
+
+  public long fsCallJsTotalTime;
+
+  public int fsCallJsTotalNum;
+
+  public long fsCallNativeTotalTime;
+
+  public int fsCallNativeTotalNum;
+
+  public int fsRequestNum;
+
+  public int fsComponentCount;
+
+  public int fsComponentCreateTime;
+
+  public int cellExceedNum;
+
+  public int timerInvokeCount;
+
+  public int fsCallEventTotalNum;
+
+  public long avgFPS;
+  public double fluency = 100D;
+
+  public long backImproveMemory;
+
+
+  /**
+   * Time spent for reading, time unit is ms.
+   */
+  public double localReadTime;
+
+  /**
+   * Name of the page
+   */
+  public String pageName = DEFAULT;
+
+  /**
+   * Size of JavaScript framework, the unit is KB
+   */
+  public double JSLibSize;
+
+  /**
+   * Time of initial JavaScript library
+   */
+  public long JSLibInitTime;
+
+  /**
+   * Size of JavaScript template
+   */
+  public double JSTemplateSize;
+
+  public long templateLoadTime;
+
+  /**
+   * Use {@link #callCreateInstanceTime} instead.
+   */
+  @Deprecated
+  public long communicateTime;
+
+  /**
+   * Time spent when rendering first screen
+   */
+  public long screenRenderTime;
+
+  /**
+   * Call native Time spent when rendering first screen
+   */
+  public long callBridgeTime;
+
+  /**
+   * Create Instance Time spent when rendering first screen
+   */
+  public long firstScreenJSFExecuteTime;
+
+  /**
+   * Call native Time spent when rendering first screen
+   */
+  public long parseJsonTime;
+
+  /**
+   * CssLayout Time spent when rendering first screen
+   */
+  public long cssLayoutTime;
+
+  /**
+   * Time spent, the unit is micro second
+   */
+  public double totalTime;
+
+  /**
+   * load bundle js time, unite ms
+   */
+  public long networkTime;
+
+  /**
+   * pure network time;
+   */
+  public long pureNetworkTime;
+
+  public long actualNetworkTime;
+  public long packageSpendTime;
+  public long syncTaskTime;
+  /**
+   * view hierarchy
+   */
+  public int maxDeepViewLayer;
+
+  public int maxDeepVDomLayer;
+
+  public double wrongImgSizeCount;
+
+  /**
+   * 1:true
+   * 0:false
+   */
+  public int useScroller = 0;
+
+  /**
+   * component Count
+   */
+  public long componentCount;
+
+  public long componentCreateTime;
+  /**
+   * Version of JavaScript libraray
+   */
+  public String JSLibVersion = WXEnvironment.JS_LIB_SDK_VERSION;
+
+  /**
+   * Version of Weex SDK
+   */
+  public String WXSDKVersion = WXEnvironment.WXSDK_VERSION;
+
+  /**
+   * The detail message of render failure
+   */
+  public String renderFailedDetail;
+
+  /**
+   * Error code
+   */
+  public String errCode;
+
+  /**
+   * Error message
+   */
+  @Deprecated
+  public String errMsg;
+  private StringBuilder mErrMsgBuilder;
+
+  public String args="";
+
+  public String connectionType;
+  public String requestType="other";
+
+  public String zCacheInfo;
+
+  /**
+   *for network tracker
+   */
+
+  /**
+   * TODO These dimensions will be moved to elsewhere
+   */
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  @Deprecated
+  public String wxDims[] = new String[5];
+
+  /**
+   * TODO These dimensions will be moved to elsewhere
+   */
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  @Deprecated
+  public long measureTimes[] = new long[5];
+
+
+  /**
+   * RenderAction
+   */
+  public int mActionAddElementCount = 0;
+  public int mActionAddElementSumTime = 0;
+
+  private String mInstanceId;
+
+  public WXPerformance(String instanceId){
+    mErrMsgBuilder=new StringBuilder();
+    mInstanceId = instanceId;
+  }
+
+  public Map<String, Double> getMeasureMap() {
+    double fsRenderTime;
+    if (this.fsRenderTime != 0) {
+      fsRenderTime = this.fsRenderTime - renderTimeOrigin;
+    } else {
+      if (totalTime != 0) {
+        fsRenderTime = totalTime;
+      } else {
+        fsRenderTime = -1;
+      }
+    }
+    Map<String, Double> quotas = new HashMap<>();
+    quotas.put(Measure.JSLibSize.toString(), JSLibSize);
+    quotas.put(Measure.JSLibInitTime.toString(), (double) JSLibInitTime);
+    quotas.put(Measure.SDKInitTime.toString(), (double) WXEnvironment.sSDKInitTime);
+    quotas.put(Measure.SDKInitInvokeTime.toString(), (double) WXEnvironment.sSDKInitInvokeTime);
+    quotas.put(Measure.SDKInitExecuteTime.toString(), (double) WXEnvironment.sSDKInitExecuteTime);
+    quotas.put(Measure.JSTemplateSize.toString(), JSTemplateSize);
+    quotas.put(Measure.pureNetworkTime.toString(), (double) pureNetworkTime);
+    quotas.put(Measure.networkTime.toString(), (double) networkTime);
+    quotas.put(Measure.fsCreateInstanceTime.toString(), (double) callCreateInstanceTime);
+    quotas.put(Measure.fsCallJsTotalTime.toString(), (double) fsCallJsTotalTime);
+    quotas.put(Measure.fsCallJsTotalNum.toString(), (double) fsCallJsTotalNum);
+    quotas.put(Measure.fsCallNativeTotalTime.toString(), (double) fsCallNativeTotalTime);
+    quotas.put(Measure.fsCallNativeTotalNum.toString(), (double) fsCallNativeTotalNum);
+    quotas.put(Measure.fsComponentCount.toString(),(double)fsComponentCount);
+    quotas.put(Measure.fsComponentCreateTime.toString(),(double)fsComponentCreateTime);
+    quotas.put(Measure.fsRenderTime.toString(), fsRenderTime);
+    quotas.put(Measure.fsRequestNum.toString(), (double) fsRequestNum);
+    quotas.put(Measure.communicateTotalTime.toString(), totalTime);
+    quotas.put(Measure.maxDeepViewLayer.toString(), (double) maxDeepViewLayer);
+    quotas.put(Measure.maxDeepVDomLayer.toString(), (double) maxDeepVDomLayer);
+    quotas.put(Measure.componentCount.toString(), (double) componentCount);
+    quotas.put(Measure.componentCreateTime.toString(),(double)componentCreateTime);
+    quotas.put(Measure.cellExceedNum.toString(), (double) cellExceedNum);
+    quotas.put(Measure.timerCount.toString(), (double) timerInvokeCount);
+    quotas.put(Measure.avgFps.toString(), (double) avgFPS);
+    quotas.put(Measure.fluency.toString(), fluency);
+    quotas.put(Measure.MaxImproveMemory.toString(), 0D);
+    quotas.put(Measure.BackImproveMemory.toString(), (double) backImproveMemory);
+    quotas.put(Measure.PushImproveMemory.toString(), 0D);
+
+    quotas.put(Measure.fsCallEventTotalNum.toString(), (double) fsCallEventTotalNum);
+    quotas.put(Measure.callCreateFinishTime.toString(), (double) callCreateFinishTime);
+    quotas.put(Measure.imgSizeCount.toString(), wrongImgSizeCount);
+    quotas.put(Measure.interactionTime.toString(), (double) interactionTime);
+    quotas.put(Measure.interactionViewAddCount.toString(), (double) interactionViewAddCount);
+    quotas.put(Measure.interactionViewAddLimitCount.toString(), (double) interactionViewAddLimitCount);
+    quotas.put(Measure.newFsRenderTime.toString(), (double) newFsRenderTime);
+
+    quotas.put(Measure.callBridgeTime.toString(), (double) callBridgeTime);
+    quotas.put(Measure.cssLayoutTime.toString(), (double) cssLayoutTime);
+    quotas.put(Measure.parseJsonTime.toString(), (double) parseJsonTime);
+
+    // TODO the following attribute is no longer needed and will be deleted soon.
+    quotas.put(Measure.screenRenderTime.toString(), (double) screenRenderTime);
+    quotas.put(Measure.communicateTime.toString(), (double) communicateTime);
+    quotas.put(Measure.localReadTime.toString(), localReadTime);
+    quotas.put(Measure.templateLoadTime.toString(), (double) templateLoadTime);
+    quotas.put(Measure.firstScreenJSFExecuteTime.toString(), (double) firstScreenJSFExecuteTime);
+    quotas.put(Measure.actualNetworkTime.toString(), (double) actualNetworkTime);
+    quotas.put(Measure.syncTaskTime.toString(), (double) syncTaskTime);
+    quotas.put(Measure.packageSpendTime.toString(), (double) packageSpendTime);
+
+    // TODO These attribute will be moved to elsewhere
+    quotas.put(Measure.measureTime1.toString(), (double) measureTimes[0]);
+    quotas.put(Measure.measureTime2.toString(), (double) measureTimes[1]);
+    quotas.put(Measure.measureTime3.toString(), (double) measureTimes[2]);
+    quotas.put(Measure.measureTime4.toString(), (double) measureTimes[3]);
+    quotas.put(Measure.measureTime5.toString(), (double) measureTimes[4]);
+    return quotas;
+  }
+
+  public Map<String, String> getDimensionMap() {
+    Map<String, String> quotas = new HashMap<>();
+    quotas.put(Dimension.JSLibVersion.toString(), JSLibVersion);
+    quotas.put(Dimension.WXSDKVersion.toString(), WXSDKVersion);
+    quotas.put(Dimension.pageName.toString(), pageName);
+    quotas.put(Dimension.requestType.toString(), requestType);
+    quotas.put(Dimension.networkType.toString(), "unknown");
+    quotas.put(Dimension.connectionType.toString(), connectionType);
+    quotas.put(Dimension.zcacheInfo.toString(), zCacheInfo);
+    quotas.put(Dimension.cacheType.toString(), cacheType);
+    quotas.put(Dimension.useScroller.toString(), String.valueOf(useScroller));
+
+    WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
+    String keyActivity = WXInstanceApm.KEY_PAGE_PROPERTIES_CONTAINER_NAME;
+    quotas.put(keyActivity, null == sdkInstance? "unKnow" : sdkInstance.getContainerInfo().get(keyActivity));
+    String keyType = WXInstanceApm.KEY_PAGE_PROPERTIES_INSTANCE_TYPE;
+    quotas.put(keyType,sdkInstance == null ?"unKnow": sdkInstance.getContainerInfo().get(keyType));
+    String keyParentPae = WXInstanceApm.KEY_PAGE_PROPERTIES_PARENT_PAGE;
+    quotas.put(keyParentPae,null == sdkInstance ?"unKnow":sdkInstance.getContainerInfo().get(keyParentPae));
+
+    // TODO These attribute will be moved to elsewhere
+    // Extra Dimension for 3rd developers.
+    quotas.put(Dimension.wxdim1.toString(), wxDims[0]);
+    quotas.put(Dimension.wxdim2.toString(), wxDims[1]);
+    quotas.put(Dimension.wxdim3.toString(), wxDims[2]);
+    quotas.put(Dimension.wxdim4.toString(), wxDims[3]);
+    quotas.put(Dimension.wxdim5.toString(), wxDims[4]);
+
+    // TODO the following attribute is no longer needed and will be deleted soon.
+    quotas.put(Dimension.bizType.toString(), bizType);
+    quotas.put(Dimension.templateUrl.toString(), templateUrl);
+    return quotas;
+  }
+
+  public static String[] getDimensions() {
+    List<String> ret = new LinkedList<>();
+    for (Dimension dimension : Dimension.values()) {
+      ret.add(dimension.toString());
+    }
+    return ret.toArray(new String[ret.size()]);
+  }
+
+  public static String[] getMeasures() {
+    List<String> ret = new LinkedList<>();
+    for (Measure measure : Measure.values()) {
+      ret.add(measure.toString());
+    }
+    return ret.toArray(new String[ret.size()]);
+  }
+
+  @Override
+  public String toString() {
+    if (WXEnvironment.isApkDebugable()) {
+      return "bizType:" + bizType + ",pageName:" + pageName + ",templateLoadTime" + templateLoadTime
+              + ",localReadTime:" + localReadTime + ",JSLibInitTime:" + JSLibInitTime
+              + ",JSLibSize:" + JSLibSize + ",templateUrl" + templateUrl
+              + ",JSTemplateSize:" + JSTemplateSize + ",communicateTime:" + communicateTime
+              + ",screenRenderTime:" + screenRenderTime
+              + ",firstScreenJSFExecuteTime:" + firstScreenJSFExecuteTime
+              + ",componentCount:" + componentCount
+              + ",syncTaskTime:" + syncTaskTime
+              + ",pureNetworkTime:" + pureNetworkTime
+              + ",networkTime:" + networkTime
+              + ",actualNetworkTime:" + actualNetworkTime
+              + ",packageSpendTime:" + packageSpendTime
+              + ",connectionType:" + connectionType
+              + ",requestType:" + requestType
+              + ",initInvokeTime:" + WXEnvironment.sSDKInitInvokeTime + ",initExecuteTime:" + WXEnvironment.sSDKInitExecuteTime
+              + ",SDKInitTime:" + WXEnvironment.sSDKInitTime
+              + ",totalTime:" + totalTime + ",JSLibVersion:" + JSLibVersion + ",WXSDKVersion:" + WXSDKVersion
+              + ",errCode:" + errCode + ",renderFailedDetail:" + renderFailedDetail
+              + ",arg:" + args
+              + ",errMsg:" + getErrMsg();
+    }
+    return super.toString();
+  }
+
+  public String getPerfData() {
+    return "networkTime:" + networkTime
+            + " actualNetworkTime:" + actualNetworkTime
+            + " connectionType:" + connectionType
+            + " requestType:" + requestType
+            + " firstScreenRenderTime:" + screenRenderTime
+            + " firstScreenJSFExecuteTime:" + firstScreenJSFExecuteTime
+            + " componentCount:" + componentCount
+            + " JSTemplateSize:" + JSTemplateSize
+            + " SDKInitTime:" + WXEnvironment.sSDKInitTime
+            + " totalTime:" + totalTime
+            + " JSLibVersion:" + JSLibVersion
+            + " WXSDKVersion:" + WXSDKVersion
+            + " pageName:" + pageName
+            + " useScroller:" + useScroller;
+
+  }
+
+  public String getErrMsg() {
+    return mErrMsgBuilder.toString();
+  }
+
+  public void appendErrMsg(CharSequence msg) {
+    mErrMsgBuilder.append(msg);
+  }
+
+  public void beforeInstanceRender(String instanceId) {
+    renderTimeOrigin = System.currentTimeMillis();
+    renderUnixTimeOrigin = WXUtils.getFixUnixTime();
+  }
+
+  public void afterInstanceDestroy(String instanceId) {
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXRefreshData.java b/android/sdk/src/main/java/org/apache/weex/common/WXRefreshData.java
new file mode 100644
index 0000000..02d6696
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXRefreshData.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public class WXRefreshData {
+
+  public String data;
+
+  public boolean isDirty;
+
+  public WXRefreshData(String data, boolean isDirty) {
+    this.data = data;
+    this.isDirty = isDirty;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXRenderStrategy.java b/android/sdk/src/main/java/org/apache/weex/common/WXRenderStrategy.java
new file mode 100644
index 0000000..2dcc5cd
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXRenderStrategy.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public enum WXRenderStrategy {
+  APPEND_ASYNC("APPEND_ASYNC"),
+  APPEND_ONCE("APPEND_ONCE"),
+  DATA_RENDER("DATA_RENDER"),
+  DATA_RENDER_BINARY("DATA_RENDER_BINARY"),
+  JSON_RENDER("JSON_RENDER");
+
+
+  private String flag;
+
+  WXRenderStrategy(String flag) {
+    this.flag = flag;
+  }
+
+  public String getFlag() {
+    return flag;
+  }
+}
+
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXRequest.java b/android/sdk/src/main/java/org/apache/weex/common/WXRequest.java
new file mode 100644
index 0000000..d0aa52c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXRequest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import org.apache.weex.WXSDKInstance;
+
+import java.util.Map;
+
+public class WXRequest {
+
+  /**
+   * The request parameter
+   */
+  public Map<String, String> paramMap;
+
+  /**
+   * The request URL
+   */
+  public String url;
+  /**
+   * The request method
+   */
+  public String method;
+  /**
+   * The request body
+   */
+  public String body;
+
+  /**
+   * The request time out
+   */
+  public int timeoutMs = WXRequest.DEFAULT_TIMEOUT_MS;
+
+  /**
+   * The default timeout
+   */
+  public static final int DEFAULT_TIMEOUT_MS = 3000;
+
+  /**
+   * running weex instanceId
+   * @see WXSDKInstance#mInstanceId
+   */
+  public String instanceId;;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXRequestListener.java b/android/sdk/src/main/java/org/apache/weex/common/WXRequestListener.java
new file mode 100644
index 0000000..f261ac9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXRequestListener.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+
+public interface WXRequestListener {
+
+  void onSuccess(int requestType, Object context, WXResponse response);
+
+  void onError(int requestType, Object context, WXResponse response);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXResponse.java b/android/sdk/src/main/java/org/apache/weex/common/WXResponse.java
new file mode 100644
index 0000000..4c209cc
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXResponse.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import java.util.Map;
+
+public class WXResponse {
+
+  /**
+   * Status code
+   */
+  public String statusCode;
+
+  /**
+   * Byte stream fetched from the connection
+   */
+  public String data;
+
+  public byte[] originalData;
+
+  /**
+   * Server internal error
+   */
+  public String errorCode;
+
+  /**
+   * Server error message
+   */
+  public String errorMsg;
+
+  /**
+   * Message for toast
+   */
+  public String toastMsg;
+
+  /**
+   * Parameter for further extension.
+   */
+  public Map<String, Object> extendParams;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXRuntimeException.java b/android/sdk/src/main/java/org/apache/weex/common/WXRuntimeException.java
new file mode 100644
index 0000000..0673f8d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXRuntimeException.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+public class WXRuntimeException extends RuntimeException {
+
+  private static final long serialVersionUID = 5732315311747521491L;
+
+  public WXRuntimeException(String e) {
+    super(e);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXThread.java b/android/sdk/src/main/java/org/apache/weex/common/WXThread.java
new file mode 100644
index 0000000..f9ee2f4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXThread.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import android.os.Handler;
+import android.os.Handler.Callback;
+import android.os.HandlerThread;
+import android.os.Message;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.tools.LogDetail;
+
+import java.lang.ref.WeakReference;
+import org.apache.weex.utils.tools.TimeCalculator;
+
+/**
+ * Thread used in weex
+ */
+public class WXThread extends HandlerThread {
+
+  private Handler mHandler;
+
+  static class SafeRunnable implements Runnable {
+
+    static final String TAG = "SafeRunnable";
+    private LogDetail mTimelineLog = null;
+    private WeakReference<WXSDKInstance> mInstance;
+    final Runnable mTask;
+    SafeRunnable(Runnable task){
+      this(task,null);
+    }
+
+    SafeRunnable(Runnable task, String taskName){
+      this(task,null, taskName);
+    }
+
+    SafeRunnable(Runnable runnable, WXSDKInstance instance, String taskName) {
+      mTask = runnable;
+      if(taskName != null) {
+        mTimelineLog = new LogDetail();
+        mTimelineLog.info.platform = TimeCalculator.PLATFORM_ANDROID;
+        mTimelineLog.name(taskName);
+        mInstance = new WeakReference<>(instance);
+      }
+    }
+
+    @Override
+    public void run() {
+      try {
+        if(mTask != null) {
+          if (mTimelineLog != null)
+            mTimelineLog.taskStart();
+          mTask.run();
+          if (mTimelineLog != null)
+            mTimelineLog.taskEnd();
+        }
+      }catch (Throwable e){
+        //catch everything may throw from exection.
+        if(WXEnvironment.isApkDebugable()){
+          WXLogUtils.e(TAG,"SafeRunnable run throw expection:"+e.getMessage());
+          throw e;
+        }
+        WXLogUtils.w(TAG, e);
+      }
+
+      if (mTimelineLog != null) {
+        if(mInstance != null) {
+          WXSDKInstance wxsdkInstance = mInstance.get();
+          if(wxsdkInstance != null) {
+            wxsdkInstance.mTimeCalculator.addLog(mTimelineLog);
+          }
+        }
+      }
+
+    }
+  }
+
+  static class SafeCallback implements Callback {
+    static final String TAG = "SafeCallback";
+
+    final Callback mCallback;
+    SafeCallback(Callback cb){
+      mCallback = cb;
+    }
+
+    @Override
+    public boolean handleMessage(Message msg) {
+      boolean result = false;
+      try{
+        if(mCallback != null){
+          result = mCallback.handleMessage(msg);
+        }
+      }catch (Throwable e){
+        //catch everything may throw from exection.
+        if(WXEnvironment.isApkDebugable()){
+          WXLogUtils.e(TAG,"SafeCallback handleMessage throw expection:"+e.getMessage());
+          throw e;
+        }
+      }
+      return result;
+    }
+  }
+
+  /**
+   * Secure Runnable to prevent throw during execution.
+   * NOTE: DO NOT use this method to wrap runnable that may be removed by {@link Handler#removeCallbacks(Runnable)}
+   * @param runnable
+   * @return
+   */
+  public static Runnable secure(Runnable runnable){
+    return secure(runnable, null, null);
+  }
+
+
+  public static Runnable secure(Runnable runnable, WXSDKInstance instance, String runnableName){
+    if(runnable == null || runnable instanceof SafeRunnable){
+      return runnable;
+    }
+    return new SafeRunnable(runnable,instance, runnableName);
+  }
+
+  public static Callback secure(Callback callback){
+    if(callback == null || callback instanceof SafeCallback){
+      return callback;
+    }
+
+    return new SafeCallback(callback);
+  }
+
+  /**
+   * @param name name of thread
+   */
+  public WXThread(String name) {
+    super(name);
+    start();
+    mHandler = new Handler(getLooper());
+  }
+
+
+  public WXThread(String name, Callback callback) {
+    super(name);
+    start();
+    mHandler = new Handler(getLooper(), secure(callback));
+  }
+
+  /**
+   * @param name name of thread
+   * @param priority The priority to run the thread at. The value supplied must be from
+   *                 {@link android.os.Process} and not from java.lang.Thread.
+   */
+  public WXThread(String name, int priority, Callback callback) {
+    super(name, priority);
+    start();
+    mHandler = new Handler(getLooper(), secure(callback));
+  }
+
+  /**
+   * @param name name of thread
+   * @param priority The priority to run the thread at. The value supplied must be from
+   *                 {@link android.os.Process} and not from java.lang.Thread.
+   */
+  public WXThread(String name, int priority) {
+    super(name, priority);
+    start();
+    mHandler = new Handler(getLooper());
+  }
+
+  public Handler getHandler() {
+    return mHandler;
+  }
+
+  public boolean isWXThreadAlive() {
+    return (mHandler != null && getLooper() != null && isAlive());
+  }
+
+  @Override
+  public boolean quit() {
+    if (mHandler != null) {
+      mHandler.removeCallbacksAndMessages(null);
+    }
+    return super.quit();
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/common/WXWorkThreadManager.java b/android/sdk/src/main/java/org/apache/weex/common/WXWorkThreadManager.java
new file mode 100644
index 0000000..8753ca9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/common/WXWorkThreadManager.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.common;
+
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Class for managing work thread.
+ *
+ * <p>
+ *  This class is for internal purpose,
+ *  please don't use it directly unless you know what you are doing.
+ * </p>
+ */
+@RestrictTo(Scope.LIBRARY_GROUP)
+public class WXWorkThreadManager {
+
+  private ExecutorService singleThreadExecutor;
+
+  public WXWorkThreadManager() {
+    singleThreadExecutor = Executors.newSingleThreadExecutor();
+  }
+
+  public void post(Runnable task) {
+    if (singleThreadExecutor != null)
+      singleThreadExecutor.execute(task);
+  }
+
+  /**
+   * Destroy current instance
+   */
+  public void destroy() {
+    if (singleThreadExecutor != null)
+      singleThreadExecutor.shutdown();
+    singleThreadExecutor = null;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/CSSConstants.java b/android/sdk/src/main/java/org/apache/weex/dom/CSSConstants.java
new file mode 100755
index 0000000..70a7a8c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/CSSConstants.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+public class CSSConstants {
+
+  public static final float UNDEFINED = Float.NaN;
+
+  public static boolean isUndefined(float value) {
+    return Float.compare(value, UNDEFINED) == 0;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/CSSShorthand.java b/android/sdk/src/main/java/org/apache/weex/dom/CSSShorthand.java
new file mode 100644
index 0000000..9c20d86
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/CSSShorthand.java
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.text.TextUtils;
+import org.apache.weex.dom.CSSShorthand.CSSProperty;
+import java.util.Arrays;
+
+public class CSSShorthand<T extends Enum<? extends CSSProperty>> implements Cloneable {
+
+  interface CSSProperty{
+  }
+
+  public static enum EDGE implements CSSProperty{
+    TOP, BOTTOM, LEFT, RIGHT, ALL;
+  }
+
+  public static enum CORNER implements CSSProperty{
+    BORDER_TOP_LEFT, BORDER_TOP_RIGHT,
+    BORDER_BOTTOM_RIGHT, BORDER_BOTTOM_LEFT, ALL;
+  }
+
+  public static enum TYPE {
+    MARGIN, PADDING, BORDER;
+  }
+
+  private float[] values;
+
+  public CSSShorthand(float []values){
+    replace(values);
+  }
+
+  public CSSShorthand() {
+    this(false);
+  }
+
+  CSSShorthand(boolean fillWithNaN) {
+    values = new float[Math.max(EDGE.values().length,CORNER.values().length)];
+    if (fillWithNaN) {
+      Arrays.fill(values, Float.NaN);
+    }
+  }
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public void set(@NonNull EDGE edge, float value){
+    setInternal(edge, value);
+  }
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public void set(@NonNull CORNER edge, float value) {
+    setInternal(edge, value);
+  }
+
+  /**
+   * {@link EDGE#ALL} is not supported, 0 will be returned.
+   * @throws IndexOutOfBoundsException
+   * @param edge
+   * @return
+   */
+  public float get(@NonNull EDGE edge){
+    return getInternal(edge);
+  }
+
+  /**
+   * {@link CORNER#ALL} is not supported, 0 will be returned.
+   * @throws IndexOutOfBoundsException
+   * @param edge
+   * @return
+   */
+  public float get(@NonNull CORNER edge) {
+    return getInternal(edge);
+  }
+
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public final void replace(float []values){
+    this.values = values;
+  }
+
+  @Override
+  public CSSShorthand clone() throws CloneNotSupportedException {
+    return (CSSShorthand) super.clone();
+  }
+
+  private void setInternal(@NonNull Enum<? extends CSSProperty> edge, float value){
+    if (edge == EDGE.ALL || edge == CORNER.ALL) {
+      Arrays.fill(values, value);
+    } else {
+      values[edge.ordinal()] = value;
+    }
+  }
+
+  private float getInternal(@NonNull Enum<? extends CSSProperty> edge){
+    return (edge == EDGE.ALL || edge == CORNER.ALL) ? 0 : values[edge.ordinal()];
+  }
+
+  @Override
+  @RestrictTo(Scope.LIBRARY)
+  public String toString() {
+    return TextUtils.isEmpty(values.toString()) ? "" : Arrays.toString(values);
+  }
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/RenderContext.java b/android/sdk/src/main/java/org/apache/weex/dom/RenderContext.java
new file mode 100644
index 0000000..f54f12d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/RenderContext.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by sospartan on 23/02/2017.
+ */
+
+public interface RenderContext {
+  WXSDKInstance getInstance();
+  WXComponent getComponent(String ref);
+  WXComponent unregisterComponent(String ref);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/TextDecorationSpan.java b/android/sdk/src/main/java/org/apache/weex/dom/TextDecorationSpan.java
new file mode 100644
index 0000000..98be70a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/TextDecorationSpan.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+
+import android.support.annotation.NonNull;
+import android.text.TextPaint;
+import android.text.style.CharacterStyle;
+import android.text.style.UpdateAppearance;
+
+import org.apache.weex.ui.component.WXTextDecoration;
+
+public class TextDecorationSpan extends CharacterStyle
+    implements UpdateAppearance {
+
+  private final WXTextDecoration mTextDecoration;
+
+  public TextDecorationSpan(@NonNull WXTextDecoration wxTextDecoration) {
+    this.mTextDecoration = wxTextDecoration;
+  }
+
+  @Override
+  public void updateDrawState(TextPaint tp) {
+    switch (mTextDecoration) {
+      case LINETHROUGH:
+        tp.setUnderlineText(false);
+        tp.setStrikeThruText(true);
+        break;
+      case UNDERLINE:
+        tp.setUnderlineText(true);
+        tp.setStrikeThruText(false);
+        break;
+      case NONE:
+        tp.setUnderlineText(false);
+        tp.setStrikeThruText(false);
+        break;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/WXAttr.java b/android/sdk/src/main/java/org/apache/weex/dom/WXAttr.java
new file mode 100644
index 0000000..a04c70e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/WXAttr.java
@@ -0,0 +1,591 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.Constants.Name;
+import org.apache.weex.common.WXImageSharpen;
+import org.apache.weex.dom.binding.ELUtils;
+import org.apache.weex.dom.binding.WXStatement;
+import org.apache.weex.el.parse.Parser;
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import static org.apache.weex.dom.binding.ELUtils.COMPONENT_PROPS;
+import static org.apache.weex.dom.binding.ELUtils.EXCLUDES_BINDING;
+import static java.lang.Boolean.parseBoolean;
+
+/**
+ * store value of component attribute
+ *
+ */
+public class WXAttr implements Map<String, Object>,Cloneable {
+
+  private static final long serialVersionUID = -2619357510079360946L;
+
+  /**
+   * static attrs
+   * */
+  private @NonNull Map<String, Object> attr;
+  private Map<String, Object> writeAttr;
+
+  /**
+   * dynamic binding attrs, can be null, only weex use
+   * */
+  private ArrayMap<String, Object>  mBindingAttrs;
+
+  /**
+   * dynamic binding statement for match, can be null, only weex use
+   * */
+  private WXStatement mStatement;
+
+  public WXAttr(){
+    attr = new HashMap<>();
+  }
+
+  public WXAttr(@NonNull Map<String,Object> standardMap) {
+    attr = standardMap;
+  }
+
+  public WXAttr(@NonNull Map<String,Object> standardMap, int extra){
+    attr = standardMap;
+  }
+
+  public static String getPrefix(Map<String, Object> attr) {
+    if (attr == null) {
+      return null;
+    }
+    Object src = attr.get(Constants.Name.PREFIX);
+    if (src == null) {
+      return null;
+    }
+    return src.toString();
+  }
+
+  public static String getSuffix(Map<String, Object> attr) {
+    if (attr == null) {
+      return null;
+    }
+    Object src = attr.get(Constants.Name.SUFFIX);
+    if (src == null) {
+      return null;
+    }
+    return src.toString();
+  }
+
+  /**
+   * Compatible with value、content
+   *
+   * @return
+   */
+  public static String getValue(Map<String, Object> attr) {
+    if (attr == null) {
+      return null;
+    }
+    Object src = attr.get(Constants.Name.VALUE);
+    if (src == null) {
+      src = attr.get("content");
+      if (src == null) {
+        return null;
+      }
+    }
+    return src.toString();
+  }
+
+  public WXImageQuality getImageQuality() {
+    Object obj = containsKey(Name.QUALITY) ? get(Name.QUALITY) : get(Name.IMAGE_QUALITY);
+    WXImageQuality imageQuality = WXImageQuality.AUTO;
+    String value;
+    if (obj != null && !TextUtils.isEmpty(value = obj.toString())) {
+      try {
+        imageQuality = WXImageQuality.valueOf(value.toUpperCase(Locale.US));
+      }catch (IllegalArgumentException e){
+        WXLogUtils.e("Image", "Invalid value image quality. Only low, normal, high, original are valid");
+      }
+    }
+    return imageQuality;
+  }
+
+  public WXImageSharpen getImageSharpen() {
+    Object obj = get(Constants.Name.SHARPEN);
+    if (obj == null) {
+      obj = get(Constants.Name.IMAGE_SHARPEN);
+    }
+    if (obj == null) {
+      return WXImageSharpen.UNSHARPEN;
+    }
+    String imageSharpen = obj.toString();
+    WXImageSharpen waImageSharpen = WXImageSharpen.UNSHARPEN;
+    if (imageSharpen.equals("sharpen")) {
+      waImageSharpen = WXImageSharpen.SHARPEN;
+    }
+
+    return waImageSharpen;
+  }
+
+  public String getImageSrc() {
+    Object src = get(Constants.Name.SRC);
+    if (src == null) {
+      return null;
+    }
+    return src.toString();
+  }
+
+  public boolean canRecycled() {
+    Object obj = get(Constants.Name.RECYCLE);
+    if (obj == null) {
+      return true;
+    }
+    try {
+      return parseBoolean(String.valueOf(obj));
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] recycle:", e);
+    }
+    return true;
+  }
+
+  public boolean showIndicators() {
+    Object obj = get(Constants.Name.SHOW_INDICATORS);
+    if (obj == null) {
+      return true;
+    }
+
+    try {
+      return parseBoolean(String.valueOf(obj));
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] showIndicators:", e);
+    }
+    return true;
+  }
+
+  public boolean autoPlay() {
+    Object obj = get(Constants.Name.AUTO_PLAY);
+    if (obj == null) {
+      return false;
+    }
+
+    try {
+      return parseBoolean(String.valueOf(obj));
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] autoPlay:", e);
+    }
+    return false;
+  }
+
+  public String getScope() {
+    Object src = get(Constants.Name.SCOPE);
+    if (src == null) {
+      return null;
+    }
+    return src.toString();
+  }
+  public String getLoadMoreRetry() {
+    Object src = get(Constants.Name.LOADMORERETRY);
+    if (src == null) {
+      return null;
+    }
+    return src.toString();
+  }
+
+  public String getLoadMoreOffset() {
+    Object src = get(Constants.Name.LOADMOREOFFSET);
+    if (src == null) {
+      return null;
+    }
+    return src.toString();
+  }
+
+  public String optString(String key){
+    if(containsKey(key)){
+      Object value = get(key);
+      if (value instanceof String) {
+        return (String) value;
+      } else if (value != null) {
+        return String.valueOf(value);
+      }
+    }
+    return "";
+  }
+
+  public boolean getIsRecycleImage() {
+    Object obj = get(Constants.Name.RECYCLE_IMAGE);
+    if (obj == null) {
+      return true;
+    }
+
+    try {
+      return parseBoolean(String.valueOf(obj));
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] recycleImage:", e);
+    }
+    return false;
+  }
+  public String getScrollDirection() {
+    Object scrollDirection = get("scrollDirection");
+    if (scrollDirection == null) {
+      return "vertical";
+    }
+    return scrollDirection.toString();
+  }
+
+  public int getOrientation() {
+    String direction = getScrollDirection();
+    if(!TextUtils.isEmpty(direction)){
+      if(direction.equals(Constants.Value.HORIZONTAL)){
+        return Constants.Orientation.HORIZONTAL;
+      }
+    }
+    Object value = get(Name.ORIENTATION);
+    if(value != null && Constants.Value.HORIZONTAL.equals(value.toString())){
+      return Constants.Orientation.HORIZONTAL;
+    }
+    return Constants.Orientation.VERTICAL;
+  }
+
+  public float getElevation(int viewPortW) {
+    Object obj = get(Constants.Name.ELEVATION);
+    float ret = Float.NaN;
+    if (obj != null) {
+      String number = obj.toString();
+      if (!TextUtils.isEmpty(number)) {
+        ret = WXViewUtils.getRealSubPxByWidth(WXUtils.getFloat(number),viewPortW);
+      } else {
+        ret = 0;
+      }
+    }
+    return ret;
+  }
+
+  public float getColumnWidth(){
+
+    Object obj = get(Constants.Name.COLUMN_WIDTH);
+    if (obj == null) {
+      return Constants.Value.AUTO;
+    }
+
+    String value = String.valueOf(obj);
+    if(Constants.Name.AUTO.equals(value)){
+      return Constants.Value.AUTO;
+    }
+
+    try {
+      float columnWidth = Float.parseFloat(value);
+      return columnWidth > 0 ? columnWidth : 0;
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] getColumnWidth:", e);
+    }
+    return Constants.Value.AUTO;
+  }
+
+  public int getColumnCount() {
+
+    Object obj = get(Constants.Name.COLUMN_COUNT);
+    if (obj == null) {
+      return Constants.Value.AUTO;
+    }
+
+    String value = String.valueOf(obj);
+    if(Constants.Name.AUTO.equals(value)){
+      return Constants.Value.AUTO;
+    }
+
+    try {
+      int columnCount = Integer.parseInt(value);
+      return columnCount > 0 ? columnCount : Constants.Value.AUTO;
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] getColumnCount:", e);
+      return Constants.Value.AUTO;
+    }
+  }
+
+  public float getColumnGap() {
+
+    Object obj = get(Constants.Name.COLUMN_GAP);
+    if (obj == null) {
+      return Constants.Value.COLUMN_GAP_NORMAL;
+    }
+
+    String value = String.valueOf(obj);
+    if (Constants.Name.NORMAL.equals(value)) {
+      return Constants.Value.COLUMN_GAP_NORMAL;
+    }
+
+    try {
+      float columnGap = Float.parseFloat(value);
+      return columnGap >= 0 ? columnGap : Constants.Value.AUTO;
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] getColumnGap:", e);
+    }
+    return Constants.Value.COLUMN_GAP_NORMAL;
+  }
+
+  public int getLayoutType(){
+    Object obj = get(Constants.Name.LAYOUT);
+    if (obj == null) {
+      return WXRecyclerView.TYPE_LINEAR_LAYOUT;
+    }
+
+    try {
+      switch(String.valueOf(obj)){
+        case Constants.Value.MULTI_COLUMN :
+          return  WXRecyclerView.TYPE_STAGGERED_GRID_LAYOUT;
+        case Constants.Value.GRID :
+          return  WXRecyclerView.TYPE_GRID_LAYOUT;
+        default:
+          return WXRecyclerView.TYPE_LINEAR_LAYOUT;
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[WXAttr] getLayoutType:", e);
+    }
+    return WXRecyclerView.TYPE_LINEAR_LAYOUT;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    return attr.equals(o);
+  }
+
+  @Override
+  public int hashCode() {
+    return attr.hashCode();
+  }
+
+  @Override
+  public void clear() {
+    attr.clear();
+  }
+
+  @Override
+  public boolean containsKey(Object key) {
+    return attr.containsKey(key);
+  }
+
+  @Override
+  public boolean containsValue(Object value) {
+    return attr.containsValue(value);
+  }
+
+  @NonNull
+  @Override
+  public Set<Entry<String, Object>> entrySet() {
+    return attr.entrySet();
+  }
+
+  @Override
+  public Object get(Object key) {
+    Map<String, Object> temp = writeAttr;
+    if (null != temp) {
+      Object obj = temp.get(key);
+      if (null != obj) {
+        return obj;
+      }
+    }
+    return attr.get(key);
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return attr.isEmpty();
+  }
+
+  @NonNull
+  @Override
+  public Set<String> keySet() {
+    return attr.keySet();
+  }
+
+  @Override
+  public Object put(String key, Object value) {
+    if(addBindingAttrIfStatement(key, value)){
+      return null;
+    }
+    return attr.put(key,value);
+  }
+
+  @Override
+  public void putAll(Map<? extends String, ?> map) {
+    //this.attr.putAll(map);
+    if (this.writeAttr == null) {
+      this.writeAttr = new ArrayMap<>();
+    }
+    this.writeAttr.putAll(map);
+  }
+
+  @Override
+  public Object remove(Object key) {
+    return attr.remove(key);
+  }
+
+  @Override
+  public int size() {
+    return attr.size();
+  }
+
+  @NonNull
+  @Override
+  public Collection<Object> values() {
+    return attr.values();
+  }
+
+  /**
+   * can by null, in most contion without template list, the value is null
+   * */
+  public ArrayMap<String, Object> getBindingAttrs() {
+    return mBindingAttrs;
+  }
+
+  /**
+   * can by null, in most contion without template list, the value is null
+   * */
+  public WXStatement getStatement() {
+    return mStatement;
+  }
+
+
+  public void setBindingAttrs(ArrayMap<String, Object> mBindingAttrs) {
+    this.mBindingAttrs = mBindingAttrs;
+  }
+
+  public void setStatement(WXStatement mStatement) {
+    this.mStatement = mStatement;
+  }
+
+  public void parseStatements(){
+    if(this.attr != null){
+       this.attr = filterStatementsFromAttrs(this.attr);
+    }
+  }
+
+  /**
+   * filter dynamic state ment
+   * */
+  private Map<String, Object> filterStatementsFromAttrs(Map attrs) {
+    if(attrs == null || attrs.size() == 0){
+      return attrs;
+    }
+    Set<Map.Entry<String,Object>> entries = attrs.entrySet();
+    Iterator<Entry<String,Object>> it =  entries.iterator();
+    while (it.hasNext()){
+      Map.Entry<String,Object> entry = it.next();
+      if(COMPONENT_PROPS.equals(entry.getKey())){
+        Object blockValue = ELUtils.bindingBlock(entry.getValue());
+        entry.setValue(blockValue);
+        continue;
+      }
+      if(addBindingAttrIfStatement(entry.getKey(), entry.getValue())){
+        it.remove();
+      }
+    }
+    return attrs;
+  }
+
+  /**
+   * filter dynamic attrs and statements
+   * */
+  private boolean addBindingAttrIfStatement(String key, Object value) {
+    for(String exclude : EXCLUDES_BINDING){
+      if(key.equals(exclude)){
+        return  false;
+      }
+    }
+    if(ELUtils.isBinding(value)){
+      if(mBindingAttrs == null){
+        mBindingAttrs = new ArrayMap<String, Object>();
+      }
+      value = ELUtils.bindingBlock(value);
+      mBindingAttrs.put(key, value);
+      return  true;
+    }
+    if(WXStatement.WX_IF.equals(key)){
+      if(mStatement == null){
+        mStatement = new WXStatement();
+      }
+      if(value != null) {
+        mStatement.put(key, Parser.parse(value.toString()));
+      }
+      return  true;
+    }
+
+    if(WXStatement.WX_FOR.equals(key)){
+      if(mStatement == null){
+        mStatement = new WXStatement();
+      }
+      value = ELUtils.vforBlock(value);
+      if(value != null) {
+        mStatement.put(key, value);
+        return  true;
+      }
+    }
+
+    if(WXStatement.WX_ONCE.equals(key)){
+      if(mStatement == null){
+        mStatement = new WXStatement();
+      }
+      mStatement.put(key, true);
+    }
+    return  false;
+  }
+
+  public void skipFilterPutAll(Map<String,Object> attrs){
+    this.attr.putAll(attrs);
+  }
+
+  @UiThread
+  public void mergeAttr() {
+    if (null != this.writeAttr) {
+      this.attr.putAll(this.writeAttr);
+      this.writeAttr = null;
+    }
+  }
+
+  @Override
+  public WXAttr clone() {
+    WXAttr wxAttr = new WXAttr();
+    wxAttr.skipFilterPutAll(attr);
+    if (mBindingAttrs != null) {
+      wxAttr.mBindingAttrs = new ArrayMap<>(mBindingAttrs);
+    }
+    if (mStatement != null){
+      wxAttr.mStatement = new WXStatement(mStatement);
+    }
+    return wxAttr;
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  @Override
+  public String toString() {
+    return attr.toString();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/WXCustomStyleSpan.java b/android/sdk/src/main/java/org/apache/weex/dom/WXCustomStyleSpan.java
new file mode 100644
index 0000000..f8834d6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/WXCustomStyleSpan.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+import android.graphics.Typeface;
+import android.text.TextPaint;
+import android.text.style.MetricAffectingSpan;
+import org.apache.weex.utils.TypefaceUtil;
+
+public class WXCustomStyleSpan extends MetricAffectingSpan {
+
+  private final int mStyle;
+  private final int mWeight;
+  private final String mFontFamily;
+
+  public WXCustomStyleSpan(int fontStyle, int fontWeight, String fontFamily) {
+    mStyle = fontStyle;
+    mWeight = fontWeight;
+    mFontFamily = fontFamily;
+  }
+
+  @Override
+  public void updateDrawState(TextPaint ds) {
+    TypefaceUtil.applyFontStyle(ds, mStyle, mWeight, mFontFamily);
+  }
+
+  @Override
+  public void updateMeasureState(TextPaint paint) {
+    TypefaceUtil.applyFontStyle(paint, mStyle, mWeight, mFontFamily);
+  }
+
+  /**
+   * Returns {@link Typeface#NORMAL} or {@link Typeface#ITALIC}.
+   */
+  public int getStyle() {
+    return (mStyle == WXStyle.UNSET ? 0 : mStyle);
+  }
+
+  /**
+   * Returns {@link Typeface#NORMAL} or {@link Typeface#BOLD}.
+   */
+  public int getWeight() {
+    return (mWeight == WXStyle.UNSET ? 0 : mWeight);
+  }
+
+  /**
+   * Returns the font family set for this StyleSpan.
+   */
+  public String getFontFamily() {
+    return mFontFamily;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/WXEvent.java b/android/sdk/src/main/java/org/apache/weex/dom/WXEvent.java
new file mode 100644
index 0000000..71277f1
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/WXEvent.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+import android.support.v4.util.ArrayMap;
+
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.dom.binding.ELUtils;
+import org.apache.weex.dom.binding.JSONUtils;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Store value of component event
+ */
+public class WXEvent extends ArrayList<String> implements Serializable, Cloneable {
+
+  private static final long serialVersionUID = -8186587029452440107L;
+
+  /**
+   *  event data format
+   *  {
+   *  type: 'appear',
+   *  params: [
+   *  { '@binding': 'index' },
+   *   'static',
+   *   { '@binding': 'item.name' },
+   *  { '@binding': '$event' }
+   *  ]
+   *  }
+   * */
+  public static final String EVENT_KEY_TYPE = "type";
+  public static final String EVENT_KEY_ARGS = "params";
+
+
+  /**
+   * dynamic binding event args, can be null, only weex use
+   * */
+  private ArrayMap mEventBindingArgs;
+  private ArrayMap<String, List<Object>> mEventBindingArgsValues;
+
+
+  @Override
+  public void clear() {
+    if(mEventBindingArgs != null){
+      mEventBindingArgs.clear();
+    }
+    if(mEventBindingArgsValues != null){
+      mEventBindingArgsValues.clear();
+    }
+    super.clear();
+  }
+
+
+  public boolean remove(String o) {
+    if(mEventBindingArgs != null){
+      mEventBindingArgs.remove(o);
+    }
+    if(mEventBindingArgsValues != null){
+      mEventBindingArgsValues.remove(o);
+    }
+    return super.remove(o);
+  }
+
+  /**
+   * can by null
+   * */
+  public ArrayMap getEventBindingArgs() {
+    return mEventBindingArgs;
+  }
+
+
+  public ArrayMap<String, List<Object>> getEventBindingArgsValues() {
+    return mEventBindingArgsValues;
+  }
+
+
+  public void addEvent(Object event) {
+    if(event instanceof CharSequence){
+      if(JSONUtils.isJSON(event.toString())){
+        addEvent(JSONUtils.toJSON(event.toString()));
+        return;
+      }
+      String eventName = event.toString();
+      if(!contains(eventName)){
+        add(eventName);
+      }
+    }else if(event instanceof JSONObject){
+      JSONObject bindings = (JSONObject) event;
+      addBindingEvent(bindings);
+    }
+  }
+
+
+
+  public static String getEventName(Object event){
+    if(event instanceof CharSequence){
+      return event.toString();
+    }else if(event instanceof JSONObject){
+      JSONObject bindings = (JSONObject) event;
+      String eventName = bindings.getString(WXEvent.EVENT_KEY_TYPE);
+      return  eventName;
+    }
+    if(event == null){
+      return  null;
+    }
+    return  event.toString();
+  }
+
+
+  public void parseStatements() {
+     if(!isEmpty()){
+       for(int i=0; i<size(); i++){
+         String event =  get(i);
+         if(JSONUtils.isJSON(event)){
+           JSONObject object = JSONUtils.toJSON(event);
+           String eventName = addBindingEvent(object);
+           set(i, eventName);
+         }
+       }
+     }
+  }
+
+  private String addBindingEvent(JSONObject bindings){
+    String eventName = bindings.getString(WXEvent.EVENT_KEY_TYPE);
+    Object args = bindings.get(WXEvent.EVENT_KEY_ARGS);
+    if (eventName != null) {
+      addBindingArgsEvent(eventName, args);
+    }
+    return eventName;
+  }
+
+  private void addBindingArgsEvent(String eventName, Object args){
+    if(!contains(eventName)){
+      add(eventName);
+    }
+    if(args != null){
+      if(mEventBindingArgs == null){
+        mEventBindingArgs = new ArrayMap();
+      }
+      mEventBindingArgs.put(eventName, ELUtils.bindingBlock(args));
+    }
+  }
+
+  public void putEventBindingArgsValue(String event, List<Object> value){
+    if(mEventBindingArgsValues == null){
+      mEventBindingArgsValues = new ArrayMap();
+    }
+    if(value == null){
+      mEventBindingArgsValues.remove(event);
+    }else{
+      mEventBindingArgsValues.put(event, value);
+    }
+  }
+
+  @Override
+  public WXEvent clone() {
+    WXEvent event = new WXEvent();
+    event.addAll(this);
+    if(mEventBindingArgs != null) {
+      event.mEventBindingArgs = new ArrayMap(mEventBindingArgs);
+    }
+    event.mEventBindingArgsValues = null; //this should not be clone, it dynamic args
+    return  event;
+  }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/WXImageQuality.java b/android/sdk/src/main/java/org/apache/weex/dom/WXImageQuality.java
new file mode 100644
index 0000000..303ab2a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/WXImageQuality.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+public enum WXImageQuality {
+
+  ORIGINAL,
+
+  LOW,
+
+  NORMAL,
+
+  HIGH,
+
+  AUTO
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/WXLineHeightSpan.java b/android/sdk/src/main/java/org/apache/weex/dom/WXLineHeightSpan.java
new file mode 100644
index 0000000..8c7d279
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/WXLineHeightSpan.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+import android.graphics.Paint;
+import android.text.style.LineHeightSpan;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.utils.WXLogUtils;
+
+public class WXLineHeightSpan implements LineHeightSpan{
+
+  private int lineHeight;
+  public WXLineHeightSpan(int lineHeight){
+    this.lineHeight=lineHeight;
+  }
+
+  @Override
+  public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) {
+    if(WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("LineHeight", text + " ; start " + start + "; end " + end + "; spanstartv "
+              + spanstartv + "; v " + v + "; fm " + fm);
+    }
+    int halfLeading=(lineHeight-(fm.descent-fm.ascent))/2;
+    fm.top-=halfLeading;
+    fm.bottom+=halfLeading;
+    fm.ascent-=halfLeading;
+    fm.descent+=halfLeading;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/WXStyle.java b/android/sdk/src/main/java/org/apache/weex/dom/WXStyle.java
new file mode 100644
index 0000000..5a5fd38
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/WXStyle.java
@@ -0,0 +1,559 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom;
+
+import android.graphics.Typeface;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.v4.util.ArrayMap;
+import android.text.Layout;
+import android.text.TextUtils;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.binding.ELUtils;
+import org.apache.weex.ui.component.WXText;
+import org.apache.weex.ui.component.WXTextDecoration;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Store value of component style
+ *
+ */
+public class WXStyle implements Map<String, Object>,Cloneable {
+
+  private static final long serialVersionUID = 611132641365274134L;
+  public static final int UNSET = -1;
+
+  @NonNull
+  private Map<String,Object> mStyles;
+
+  @Nullable
+  private Map<String,Map<String,Object>> mPesudoStyleMap;// clz_group:{styleMap}
+
+  @Nullable
+  private Map<String,Object> mPesudoResetStyleMap;
+
+  /**
+   * dynamic binding attrs, can be null, only weex use
+   * */
+  private ArrayMap<String, Object>  mBindingStyle;
+
+  public WXStyle(){
+    mStyles = new ArrayMap<>();
+  }
+
+  public WXStyle(Map<String, Object> styles){
+    this.mStyles = styles;
+    processPesudoClasses(this.mStyles);
+  }
+
+  public WXStyle(Map<String, Object> mStyles, boolean byPesudo) {
+    this();
+    this.putAll(mStyles, byPesudo);
+  }
+
+  @Nullable
+  public String getBlur() {
+    if(get(Constants.Name.FILTER) == null) {
+      return null;
+    }
+    return get(Constants.Name.FILTER).toString().trim();
+  }
+
+  /*
+   * text-decoration
+   **/
+  public static WXTextDecoration getTextDecoration(Map<String, Object> style) {
+    Object obj;
+    WXTextDecoration ret;
+    if (style == null || (obj = style.get(Constants.Name.TEXT_DECORATION)) == null) {
+      ret = WXTextDecoration.NONE;
+    } else {
+      String textDecoration = obj.toString();
+      switch (textDecoration) {
+        case "underline":
+          ret = WXTextDecoration.UNDERLINE;
+          break;
+        case "line-through":
+          ret = WXTextDecoration.LINETHROUGH;
+          break;
+        case "none":
+          ret = WXTextDecoration.NONE;
+          break;
+        default:
+          ret = WXTextDecoration.INVALID;
+          break;
+      }
+    }
+    return ret;
+  }
+
+  public static String getTextColor(Map<String, Object> style) {
+    if (style == null) {
+      return "";
+    }
+    Object temp = style.get(Constants.Name.COLOR);
+    return temp == null ? "" : temp.toString();
+  }
+
+  public static int getFontWeight(Map<String, Object> style) {
+    int typeface = android.graphics.Typeface.NORMAL;
+    if (style != null) {
+      Object temp = style.get(Constants.Name.FONT_WEIGHT);
+      if (temp != null) {
+        String fontWeight = temp.toString();
+        switch (fontWeight){
+          case "600":
+          case "700":
+          case "800":
+          case "900":
+          case Constants.Value.BOLD:
+            typeface=Typeface.BOLD;
+            break;
+        }
+      }
+    }
+    return typeface;
+  }
+
+  public static int getFontStyle(Map<String, Object> style) {
+    int typeface = android.graphics.Typeface.NORMAL;
+    if (style == null) {
+      return typeface;
+    }
+    Object temp = style.get(Constants.Name.FONT_STYLE);
+    if (temp == null) {
+      return typeface;
+    }
+    String fontWeight = temp.toString();
+    if (fontWeight.equals(Constants.Value.ITALIC)) {
+      typeface = android.graphics.Typeface.ITALIC;
+    }
+    return typeface;
+  }
+
+  public static int getFontSize(Map<String, Object> style,int viewPortW) {
+    if (style == null) {
+      return (int) WXViewUtils.getRealPxByWidth(WXText.sDEFAULT_SIZE,viewPortW);
+    }
+    int fontSize = WXUtils.getInt(style.get(Constants.Name.FONT_SIZE));
+    if (fontSize <= 0) {
+      fontSize = WXText.sDEFAULT_SIZE;
+    }
+    return (int) WXViewUtils.getRealPxByWidth(fontSize,viewPortW);
+  }
+
+  public static String getFontFamily(Map<String, Object> style) {
+    String fontFamily = null;
+    if (style != null) {
+      Object temp;
+      temp = style.get(Constants.Name.FONT_FAMILY);
+      if (temp != null) {
+        fontFamily = temp.toString();
+      }
+    }
+    return fontFamily;
+  }
+
+  public static Layout.Alignment getTextAlignment(Map<String, Object> style){
+    return getTextAlignment(style, false);
+  }
+
+  public static Layout.Alignment getTextAlignment(Map<String, Object> style, boolean isRTL){
+    Layout.Alignment alignment= isRTL ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL;
+    String textAlign= (String) style.get(Constants.Name.TEXT_ALIGN);
+    if(TextUtils.equals(Constants.Value.LEFT,textAlign)){
+      alignment= Layout.Alignment.ALIGN_NORMAL;
+    }
+    else if(TextUtils.equals(Constants.Value.CENTER,textAlign)){
+      alignment= Layout.Alignment.ALIGN_CENTER;
+    }
+    else if(TextUtils.equals(Constants.Value.RIGHT,textAlign)){
+      alignment= Layout.Alignment.ALIGN_OPPOSITE;
+    }
+    return alignment;
+  }
+
+  public static TextUtils.TruncateAt getTextOverflow(Map<String, Object> style){
+    TextUtils.TruncateAt truncateAt=null;
+    String ellipse = (String) style.get(Constants.Name.TEXT_OVERFLOW);
+    if(TextUtils.equals(Constants.Name.ELLIPSIS,ellipse)){
+      truncateAt = TextUtils.TruncateAt.END;
+    }
+    return truncateAt;
+  }
+
+  public static int getLines(Map<String, Object> style) {
+    return WXUtils.getInt(style.get(Constants.Name.LINES));
+  }
+
+  public static int getLineHeight(Map<String, Object> style,int viewPortW){
+    if (style == null) {
+      return UNSET;
+    }
+    int lineHeight = WXUtils.getInt(style.get(Constants.Name.LINE_HEIGHT));
+    if (lineHeight <= 0) {
+      lineHeight = UNSET;
+      return lineHeight;
+    }
+    return (int) WXViewUtils.getRealPxByWidth(lineHeight,viewPortW);
+  }
+
+  public float getBorderRadius() {
+    float temp = WXUtils.getFloat(get(Constants.Name.BORDER_RADIUS));
+    if (WXUtils.isUndefined(temp)) {
+      return Float.NaN;
+    }
+    return temp;
+  }
+
+  public String getBorderColor() {
+    Object color = get(Constants.Name.BORDER_COLOR);
+    return color == null ? null : color.toString();
+  }
+
+  public String getBorderStyle() {
+    Object borderStyle = get(Constants.Name.BORDER_STYLE);
+    return borderStyle == null ? null : borderStyle.toString();
+  }
+
+  public boolean isSticky() {
+    Object position = get(Constants.Name.POSITION);
+    if (position == null) {
+      return false;
+    }
+    return position.toString().equals(Constants.Value.STICKY);
+  }
+
+  public boolean isFixed() {
+    Object position = get(Constants.Name.POSITION);
+    if (position == null) {
+      return false;
+    }
+    return position.toString().equals(Constants.Value.FIXED);
+  }
+
+  public float getLeft() {
+    float temp = WXUtils.getFloat(get(Constants.Name.LEFT));
+    if (WXUtils.isUndefined(temp)) {
+      return Float.NaN;
+    }
+    return temp;
+  }
+
+  public float getRight() {
+    float temp = WXUtils.getFloat(get(Constants.Name.RIGHT));
+    if (WXUtils.isUndefined(temp)) {
+      return Float.NaN;
+    }
+    return temp;
+  }
+
+  public float getTop() {
+    float temp = WXUtils.getFloat(get(Constants.Name.TOP));
+    if (WXUtils.isUndefined(temp)) {
+      return Float.NaN;
+    }
+    return temp;
+  }
+
+  public float getBottom() {
+    float temp = WXUtils.getFloat(get(Constants.Name.BOTTOM));
+    if (WXUtils.isUndefined(temp)) {
+      return Float.NaN;
+    }
+    return temp;
+  }
+
+  /*
+   * others
+   **/
+  public String getBackgroundColor() {
+    Object temp = get(Constants.Name.BACKGROUND_COLOR);
+    return temp == null ? "" : temp.toString();
+  }
+
+  public int getTimeFontSize() {
+    int fontSize = WXUtils.getInt(get("timeFontSize"));
+    if (fontSize <= 0) {
+      fontSize = WXText.sDEFAULT_SIZE;
+    }
+    return fontSize;
+  }
+
+  public float getOpacity() {
+    Object object = get(Constants.Name.OPACITY);
+    float opacity = 1;
+    if (object == null) {
+      return opacity;
+    }
+    return WXUtils.getFloat(object);
+  }
+
+  public String getOverflow() {
+    Object obj = get(Constants.Name.OVERFLOW);
+    return obj == null ? Constants.Value.VISIBLE : obj.toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    return mStyles.equals(o);
+  }
+
+  @Override
+  public int hashCode() {
+    return mStyles.hashCode();
+  }
+
+  @Override
+  public void clear() {
+    mStyles.clear();
+  }
+
+  @Override
+  public boolean containsKey(Object key) {
+    return mStyles.containsKey(key);
+  }
+
+  @Override
+  public boolean containsValue(Object value) {
+    return mStyles.containsValue(value);
+  }
+
+  @NonNull
+  @Override
+  public Set<Entry<String, Object>> entrySet() {
+    return mStyles.entrySet();
+  }
+
+  @Override
+  public Object get(Object key) {
+    return mStyles.get(key);
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return mStyles.isEmpty();
+  }
+
+  @NonNull
+  @Override
+  public Set<String> keySet() {
+    return mStyles.keySet();
+  }
+
+  @Override
+  public Object put(String key, Object value) {
+    if(addBindingStyleIfStatement(key, value)){
+      return null;
+    }
+    return mStyles.put(key,value);
+  }
+
+  @Override
+  public void putAll(Map<? extends String, ?> map) {
+    this.mStyles.putAll(map);
+  }
+
+  /**
+   * Used by Dom Thread, new and update styles.
+   * @param map
+   * @param byPesudo
+   */
+  public void putAll(Map<? extends String, ?> map, boolean byPesudo) {
+    this.mStyles.putAll(map);
+    if (!byPesudo) {
+      processPesudoClasses(map);
+    }
+  }
+
+  public void updateStyle(Map<? extends String, ?> map, boolean byPesudo){
+      parseBindingStylesStatements(map);
+      putAll(map, byPesudo);
+  }
+
+
+  public Map<String, Object> getPesudoResetStyles() {
+    if(mPesudoResetStyleMap == null){
+      mPesudoResetStyleMap = new ArrayMap<>();
+    }
+    return mPesudoResetStyleMap;
+  }
+
+  public Map<String, Map<String, Object>> getPesudoStyles() {
+    if(mPesudoStyleMap == null){
+      mPesudoStyleMap = new ArrayMap<>();
+    }
+    return mPesudoStyleMap;
+  }
+
+  <T extends String, V> void processPesudoClasses(Map<T, V> styles) {
+    Map<String, Object> tempMap = null;
+    for(Map.Entry<T, V> entry:styles.entrySet()){
+      //Key Format: "style-prop:pesudo_clz1:pesudo_clz2"
+      String key = entry.getKey();
+      int i;
+      if ((i = key.indexOf(":")) > 0) {
+        initPesudoMapsIfNeed(styles);
+        String clzName = key.substring(i);
+        if (clzName.equals(Constants.PSEUDO.ENABLED)) {
+          //enabled, use as regular style
+          String styleKey = key.substring(0, i);
+          if(tempMap == null){
+            tempMap = new ArrayMap<>();
+          }
+          tempMap.put(styleKey, entry.getValue());
+          mPesudoResetStyleMap.put(styleKey, entry.getValue());
+          continue;
+        } else {
+          clzName = clzName.replace(Constants.PSEUDO.ENABLED, "");//remove ':enabled' which is ignored
+        }
+
+        Map<String, Object> stylesMap = mPesudoStyleMap.get(clzName);
+        if (stylesMap == null) {
+          stylesMap = new ArrayMap<>();
+          mPesudoStyleMap.put(clzName, stylesMap);
+        }
+        stylesMap.put(key.substring(0, i), entry.getValue());
+      }
+    }
+
+    if (tempMap != null && !tempMap.isEmpty()) {
+      this.mStyles.putAll(tempMap);
+    }
+  }
+
+  @Override
+  public Object remove(Object key) {
+    return mStyles.remove(key);
+  }
+
+  @Override
+  public int size() {
+    return mStyles.size();
+  }
+
+  @NonNull
+  @Override
+  public Collection<Object> values() {
+    return mStyles.values();
+  }
+
+
+
+  private void initPesudoMapsIfNeed(Map<? extends String, ?> styles){
+    if(mPesudoStyleMap == null){
+      mPesudoStyleMap = new ArrayMap<>();
+    }
+    if(mPesudoResetStyleMap == null){
+      mPesudoResetStyleMap = new ArrayMap<>();
+    }
+    if(mPesudoResetStyleMap.isEmpty()){
+      mPesudoResetStyleMap.putAll(styles);
+    }
+  }
+
+
+
+  public void  parseStatements(){
+    if(this.mStyles != null){
+      this.mStyles = parseBindingStylesStatements(this.mStyles);
+    }
+  }
+
+  /**
+   * filter dynamic state ment
+   * */
+  private Map<String, Object> parseBindingStylesStatements(Map styles) {
+    if(styles == null || styles.size() == 0){
+      return styles;
+    }
+    Set<Map.Entry<String,Object>> entries = styles.entrySet();
+    Iterator<Entry<String,Object>> it =  entries.iterator();
+    while (it.hasNext()){
+      Map.Entry<String,Object> entry = it.next();
+      if(addBindingStyleIfStatement(entry.getKey(), entry.getValue())){
+        if(mPesudoStyleMap != null){
+          mPesudoStyleMap.remove(entry.getKey());
+        }
+        if(mPesudoResetStyleMap != null){
+          mPesudoResetStyleMap.remove(entry.getKey());
+        }
+        it.remove();
+      }
+    }
+    return styles;
+  }
+
+  /**
+   * filter dynamic attrs and statements
+   * */
+  private boolean addBindingStyleIfStatement(String key, Object value) {
+    if(ELUtils.isBinding(value)){
+      if(mBindingStyle == null){
+        mBindingStyle = new ArrayMap<String, Object>();
+      }
+      value = ELUtils.bindingBlock(value);
+      mBindingStyle.put(key, value);
+      return  true;
+    }
+    return  false;
+  }
+
+  public ArrayMap<String, Object> getBindingStyle() {
+    return mBindingStyle;
+  }
+
+  @Override
+  public WXStyle clone(){
+    WXStyle style = new WXStyle();
+    style.mStyles.putAll(this.mStyles);
+    if(mBindingStyle != null){
+      style.mBindingStyle = new ArrayMap<>(mBindingStyle);
+    }
+    if(mPesudoStyleMap != null) {
+      style.mPesudoStyleMap = new ArrayMap<>();
+      for (Entry<String, Map<String, Object>> entry : this.mPesudoStyleMap.entrySet()) {
+        Map<String, Object> valueClone = new ArrayMap<>();
+        valueClone.putAll(entry.getValue());
+        style.mPesudoStyleMap.put(entry.getKey(), valueClone);
+      }
+    }
+
+    if(mPesudoResetStyleMap!=null) {
+      style.mPesudoResetStyleMap = new ArrayMap<>();
+      style.mPesudoResetStyleMap.putAll(this.mPesudoResetStyleMap);
+    }
+
+
+    return style;
+  }
+
+  @Override
+  @RestrictTo(Scope.LIBRARY)
+  public String toString() {
+    return mStyles.toString();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/binding/ELUtils.java b/android/sdk/src/main/java/org/apache/weex/dom/binding/ELUtils.java
new file mode 100644
index 0000000..482e8c8
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/binding/ELUtils.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom.binding;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.el.parse.Parser;
+import org.apache.weex.el.parse.Token;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.Set;
+
+/**
+ * util's for binding and statment
+ * Created by jianbai.gbj on 2017/8/17.
+ */
+public class ELUtils {
+
+    public static final String BINDING = "@binding";
+    /**
+     * sub template
+     * */
+    public static final String IS_COMPONENT_ROOT = "@isComponentRoot";
+
+
+    public static final String COMPONENT_PROPS = "@componentProps";
+
+    public static final  String[] EXCLUDES_BINDING = {"clickEventParams"};
+
+    /**
+     * @param value check object is binding expression
+     * */
+    public static boolean isBinding(Object value){
+        if(value instanceof JSONObject){
+            JSONObject  object = (JSONObject) value;
+            if(object.containsKey(BINDING)){
+                return  true;
+            }
+        }else if(value instanceof JSONArray){
+            JSONArray array = (JSONArray) value;
+            for(int i=0; i<array.size(); i++){
+                if(isBinding(array.get(i))){
+                    return  true;
+                }
+            }
+        }else if(value instanceof String){
+            return ((String) value).indexOf(BINDING) >= 0;
+        }
+        return  false;
+    }
+
+    /**
+     * parse binding code to block, enable fast execute
+     * */
+    public static Object bindingBlock(Object value){
+        if(value instanceof JSONObject){
+            JSONObject  object = (JSONObject) value;
+            if(object.containsKey(BINDING)){
+                Object binding = object.get(BINDING);
+                if(!(binding instanceof Token)){
+                    object.put(BINDING, Parser.parse(binding.toString()));
+                }
+            }
+            Set<String> keys = object.keySet();
+            for(Object propsKey : keys){
+                if(object.get(propsKey) instanceof  JSONObject
+                        && ((JSONObject)object.get(propsKey)).containsKey(BINDING)){
+                    JSONObject propsValue = (JSONObject) object.get(propsKey);
+                    Object binding = propsValue.get(BINDING);
+                    if(!(binding instanceof Token)){
+                        propsValue.put(BINDING, Parser.parse(binding.toString()));
+                    }
+                }
+            }
+        }else if(value instanceof JSONArray){
+            JSONArray array = (JSONArray) value;
+            for(int i=0; i<array.size(); i++){
+                bindingBlock(array.get(i));
+            }
+        }else if(value instanceof String){
+            String json = value.toString();
+            if(json.startsWith("{")){
+                return bindingBlock(JSON.parseObject(json));
+            }else if(json.startsWith("[")){
+                return bindingBlock(JSON.parseArray(json));
+            }
+        }
+        return  value;
+    }
+
+    public static Object vforBlock(Object vfor){
+        if(vfor instanceof  JSONObject){
+            if(((JSONObject) vfor).containsKey(WXStatement.WX_FOR_LIST)){
+                Object list = ((JSONObject) vfor).get(WXStatement.WX_FOR_LIST);
+                if(!(list instanceof Token)){
+                    ((JSONObject) vfor).put(WXStatement.WX_FOR_LIST, Parser.parse(list.toString()));
+                }
+            }
+        }else if(vfor instanceof  String){
+            return vforBlock(JSONObject.parseObject(vfor.toString()));
+        }else{
+            if(WXEnvironment.isApkDebugable()){
+                WXLogUtils.e("weex", "weex vfor is illegal " + vfor);
+            }
+        }
+        return vfor;
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/binding/JSONUtils.java b/android/sdk/src/main/java/org/apache/weex/dom/binding/JSONUtils.java
new file mode 100644
index 0000000..8d54f14
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/binding/JSONUtils.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom.binding;
+
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * Created by furture on 2018/5/8.
+ */
+
+public class JSONUtils {
+
+
+    public static boolean isJSON(Object json){
+        if(json instanceof JSONObject){
+            return true;
+        }
+        if(json instanceof String){
+            return ((String) json).startsWith("{");
+        }
+        return false;
+    }
+
+    public static JSONObject toJSON(Object json){
+        if(json instanceof JSONObject){
+            return (JSONObject) json;
+        }
+        return JSONObject.parseObject(json.toString());
+    }
+
+
+    public static boolean isJSON(String json){
+        return json.startsWith("{");
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/binding/WXStatement.java b/android/sdk/src/main/java/org/apache/weex/dom/binding/WXStatement.java
new file mode 100644
index 0000000..e58a583
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/binding/WXStatement.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom.binding;
+
+import android.support.v4.util.ArrayMap;
+import android.support.v4.util.SimpleArrayMap;
+
+/**
+ * Created by furture on 2017/8/17.
+ * statement expression for template list, like v-if v-for
+ */
+public class WXStatement extends ArrayMap<String, Object> implements  Cloneable  {
+
+    /**
+     * v-for statement, like
+     * <code>
+     *     <div v-for="(item, i) in dataset.panels">
+     *     <text>{{i}}: {{item.name}}</text>
+     *     </div>
+     * </code>
+     * json command:
+     * <code>
+     *      attr: {
+     *          '[[repeat]]': {
+     *          '@expression': 'dataList',
+     *          '@index': 'index',
+     *          '@alias': 'item'
+     *         }
+     *      }
+     * </code>
+     * */
+    public static final String WX_FOR = "[[repeat]]";
+    public static final String WX_FOR_INDEX = "@index";
+    public static final String WX_FOR_ITEM = "@alias";
+    public static final String WX_FOR_LIST = "@expression";
+
+
+    /**
+     * v-if statement, like:
+     * <code>
+     *   <p v-if="male">Male</p>
+     * </code>
+     * json command
+     * attr: {
+     *      '[[match]]': 'condition'
+     *    }
+     * */
+    public static final String WX_IF = "[[match]]";
+
+
+    /**
+     * once statement
+     * */
+    public static final  String WX_ONCE = "[[once]]";
+
+    public WXStatement() {
+    }
+
+    public WXStatement(SimpleArrayMap map) {
+        super(map);
+    }
+
+    @Override
+    protected WXStatement clone(){
+        return new WXStatement(this);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/dom/transition/WXTransition.java b/android/sdk/src/main/java/org/apache/weex/dom/transition/WXTransition.java
new file mode 100644
index 0000000..577b2e0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/dom/transition/WXTransition.java
@@ -0,0 +1,754 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.dom.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Handler;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.view.animation.PathInterpolatorCompat;
+import android.text.TextUtils;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.ui.animation.BackgroundColorProperty;
+import org.apache.weex.ui.animation.TransformParser;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.SingleFunctionParser;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
+import org.apache.weex.common.Constants.TimeFunction;
+
+/**
+ *   transition on dom thread
+ *   transition-property: height;
+ *   transition-duration: .3s;
+ *   transition-delay: .05s;
+ *   transition-timing-function: ease-in-out;
+ *
+ *   Created by furture on 2017/10/18.
+ */
+public class WXTransition {
+
+    public static final  String TRANSITION_PROPERTY = "transitionProperty";
+    public static final  String TRANSITION_DURATION = "transitionDuration";
+    public static final  String TRANSITION_DELAY = "transitionDelay";
+    public static final  String TRANSITION_TIMING_FUNCTION = "transitionTimingFunction";
+
+    public static final  Pattern PROPERTY_SPLIT_PATTERN = Pattern.compile("\\||,");
+
+
+    /**
+     * layout animation property
+     * */
+    private static final Set<String> LAYOUT_PROPERTIES = new HashSet<>();
+    static {
+        LAYOUT_PROPERTIES.add(Constants.Name.WIDTH);
+        LAYOUT_PROPERTIES.add(Constants.Name.HEIGHT);
+        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_TOP);
+        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_BOTTOM);
+        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_LEFT);
+        LAYOUT_PROPERTIES.add(Constants.Name.MARGIN_RIGHT);
+        LAYOUT_PROPERTIES.add(Constants.Name.LEFT);
+        LAYOUT_PROPERTIES.add(Constants.Name.RIGHT);
+        LAYOUT_PROPERTIES.add(Constants.Name.TOP);
+        LAYOUT_PROPERTIES.add(Constants.Name.BOTTOM);
+        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_LEFT);
+        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_RIGHT);
+        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_TOP);
+        LAYOUT_PROPERTIES.add(Constants.Name.PADDING_BOTTOM);
+    }
+
+    /**
+     * transform animation property, use android system animaton ability
+     * */
+    private static final Set<String> TRANSFORM_PROPERTIES = new HashSet<>();
+    static {
+        TRANSFORM_PROPERTIES.add(Constants.Name.OPACITY);
+        TRANSFORM_PROPERTIES.add(Constants.Name.BACKGROUND_COLOR);
+        TRANSFORM_PROPERTIES.add(Constants.Name.TRANSFORM);
+    }
+
+    private List<String> properties;
+    private Interpolator  interpolator;
+    private long  duration;
+    private long delay;
+    private WXComponent mWXComponent;
+    private Handler handler;
+    private ValueAnimator layoutValueAnimator;
+    private Map<String, Object> layoutPendingUpdates;
+    private ObjectAnimator transformAnimator;
+    private Map<String, Object> transformPendingUpdates;
+    private Runnable transitionEndEvent;
+    private Map<String, Object> targetStyles;
+    private Runnable animationRunnable;
+
+    private Runnable transformAnimationRunnable;
+    private volatile AtomicInteger lockToken = new AtomicInteger(0);
+
+
+    public WXTransition() {
+        this.properties = new ArrayList<>(4);
+        this.handler = new Handler();
+        this.layoutPendingUpdates = new ArrayMap<>();
+        this.transformPendingUpdates = new ArrayMap<>();
+        this.targetStyles = new ArrayMap<>();
+    }
+
+    /**
+     * create transition from map styles if style contains transitionProperty
+     * */
+    public static WXTransition fromMap(Map<String, Object> style, WXComponent component){
+        if(style.get(TRANSITION_PROPERTY) == null){
+            return  null;
+        }
+        String propertyString = WXUtils.getString(style.get(TRANSITION_PROPERTY), null);
+        if(propertyString == null){
+            return null;
+        }
+        WXTransition transition  = new WXTransition();
+        updateTransitionProperties(transition, propertyString);
+        if(transition.properties.isEmpty()){
+            return  null;
+        }
+        transition.duration = parseTimeMillis(style, TRANSITION_DURATION, 0);
+        transition.delay =  parseTimeMillis(style, TRANSITION_DELAY, 0);
+        transition.interpolator = createTimeInterpolator(WXUtils.getString(style.get(TRANSITION_TIMING_FUNCTION), null));
+        transition.mWXComponent = component;
+        return  transition;
+    }
+
+    /**
+     * check updates has transition property
+     * */
+    public boolean hasTransitionProperty(Map<String, Object> styles){
+        for(String property : properties){
+            if(styles.containsKey(property)){
+                return  true;
+            }
+        }
+        return false;
+    }
+
+    public void updateTranstionParams(Map<String, Object> updates){
+        if(updates.containsKey(TRANSITION_DELAY)){
+            mWXComponent.getStyles().put(TRANSITION_DELAY, updates.remove(TRANSITION_DELAY));
+            this.delay = parseTimeMillis(mWXComponent.getStyles(), TRANSITION_DELAY, 0);
+        }
+
+        if(updates.containsKey(TRANSITION_TIMING_FUNCTION) && updates.get(TRANSITION_TIMING_FUNCTION) != null){
+            mWXComponent.getStyles().put(TRANSITION_TIMING_FUNCTION, updates.remove(TRANSITION_TIMING_FUNCTION));
+            this.interpolator = createTimeInterpolator(mWXComponent.getStyles().get(TRANSITION_TIMING_FUNCTION).toString());
+        }
+
+        if(updates.containsKey(TRANSITION_DURATION)){
+            mWXComponent.getStyles().put(TRANSITION_DURATION, updates.remove(TRANSITION_DURATION));
+            this.duration = parseTimeMillis(mWXComponent.getStyles(), TRANSITION_DURATION, 0);
+        }
+
+        if(updates.containsKey(TRANSITION_PROPERTY)){
+            mWXComponent.getStyles().put(TRANSITION_PROPERTY, updates.remove(TRANSITION_PROPERTY));
+            updateTransitionProperties(this, WXUtils.getString(mWXComponent.getStyles().get(TRANSITION_PROPERTY), null));
+        }
+    }
+
+    /**
+     * start transition animation, updates maybe split two different updates,
+     * because javascript will send multi update on same transition, we assume that updates in 8ms is one transition
+     * */
+    public void  startTransition(Map<String, Object> updates){
+        synchronized (lockToken){
+            final View taregtView = getTargetView();
+            if(taregtView == null){
+                return;
+            }
+            final int token = lockToken.incrementAndGet();
+            for(String property : properties){
+                if(updates.containsKey(property)){
+                    Object targetValue = updates.remove(property);
+                    if(LAYOUT_PROPERTIES.contains(property)) {
+                        layoutPendingUpdates.put(property, targetValue);
+                    }else if(TRANSFORM_PROPERTIES.contains(property)){
+                        transformPendingUpdates.put(property, targetValue);
+                    }
+                }
+            }
+
+            int delay = WXUtils.getNumberInt(mWXComponent.getAttrs().get("actionDelay"), 16);
+            if(delay > duration){
+                delay = (int) duration;
+            }
+            if(animationRunnable != null) {
+                handler.removeCallbacks(animationRunnable);
+            }
+            animationRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    if(token == lockToken.get()) {
+                        doTransitionAnimation(token);
+                    }
+                    animationRunnable = null;
+                }
+            };
+            if(delay > 0){
+                handler.postDelayed(animationRunnable, delay);
+            }else{
+                animationRunnable.run();
+            }
+        }
+    }
+
+    /**
+     * doTransitionAnimation include transform and layout animation.
+     * 1. put pre transition updates from target style to dom style
+     * 2. do transform animation and layout animation
+     * */
+    private void  doTransitionAnimation(final  int token){
+        final View taregtView = getTargetView();
+        if(taregtView == null){
+            return;
+        }
+        if(targetStyles.size() > 0){
+            for(String property : properties){
+                if(!(LAYOUT_PROPERTIES.contains(property) || TRANSFORM_PROPERTIES.contains(property))){
+                    continue;
+                }
+                if(layoutPendingUpdates.containsKey(property)){
+                    continue;
+                }
+                if(transformPendingUpdates.containsKey(property)){
+                    continue;
+                }
+                synchronized (targetStyles){
+                    if(targetStyles.containsKey(property)){
+                        //reset pre transition style
+                        Object targetValue = targetStyles.remove(property);
+                        mWXComponent.getStyles().put(property, targetValue);
+//                        domObject.getStyles().put(property, targetValue);
+//                        WXComponent component = getComponent();
+//                        if(component != null && component.getDomObject() != null){
+//                            component.getDomObject().getStyles().put(property, targetValue);
+//                        }
+                    }
+                }
+            }
+        }
+
+
+
+        if(transitionEndEvent != null){
+            taregtView.removeCallbacks(transitionEndEvent);
+        }
+        if(transitionEndEvent == null && duration > Float.MIN_NORMAL){
+            transitionEndEvent = new Runnable(){
+                @Override
+                public void run() {
+                    transitionEndEvent = null;
+                    if(duration < Float.MIN_NORMAL){
+                        return;
+                    }
+                    if(mWXComponent != null && mWXComponent.getEvents().contains(Constants.Event.ON_TRANSITION_END)){
+                        mWXComponent.fireEvent(Constants.Event.ON_TRANSITION_END);
+                    }
+                }
+            };
+        }
+        if(transformAnimationRunnable != null) {
+            taregtView.removeCallbacks(transformAnimationRunnable);
+        }
+        transformAnimationRunnable = new Runnable() {
+            @Override
+            public void run() {
+                synchronized (lockToken) {
+                    if(token == lockToken.get()) {
+                        doPendingTransformAnimation(token);
+                    }
+                }
+            }
+        };
+        taregtView.post(transformAnimationRunnable);
+        doPendingLayoutAnimation();
+    }
+
+
+    /**
+     *  transform, opacity, backgroundcolor which not effect layout use android system animation in main thread.
+     * */
+    private void doPendingTransformAnimation(int token) {
+        if(transformAnimator != null){
+            transformAnimator.cancel();
+            transformAnimator = null;
+        }
+        if(transformPendingUpdates.size() == 0){
+            return;
+        }
+        final View taregtView = getTargetView();
+        if(taregtView == null){
+            return;
+        }
+        List<PropertyValuesHolder> holders = new ArrayList<>(8);
+        String transform  = WXUtils.getString(transformPendingUpdates.remove(Constants.Name.TRANSFORM), null);
+        if(!TextUtils.isEmpty(transform)){
+            Map<Property<View,Float>, Float>  properties = TransformParser
+                .parseTransForm(mWXComponent.getInstanceId(), transform, (int)mWXComponent.getLayoutWidth(), (int)mWXComponent.getLayoutHeight(), mWXComponent.getViewPortWidth());
+            PropertyValuesHolder[]  transformHolders = TransformParser.toHolders(properties);
+            for(PropertyValuesHolder holder : transformHolders){
+                holders.add(holder);
+            }
+            synchronized (targetStyles) {
+                targetStyles.put(Constants.Name.TRANSFORM, transform);
+            }
+        }
+
+        for(String property : properties){
+            if(!TRANSFORM_PROPERTIES.contains(property)){
+                continue;
+            }
+            if(!transformPendingUpdates.containsKey(property)){
+                continue;
+            }
+            Object value = transformPendingUpdates.remove(property);
+            synchronized (targetStyles) {
+                targetStyles.put(property, value);
+            }
+            switch (property){
+                case Constants.Name.OPACITY:{
+                    holders.add(PropertyValuesHolder.ofFloat(View.ALPHA, taregtView.getAlpha(), WXUtils.getFloat(value, 1.0f)));
+                    taregtView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); //hardware or none has bug on some platform
+                }
+                break;
+                case Constants.Name.BACKGROUND_COLOR:{
+                    int fromColor = WXResourceUtils.getColor(WXUtils.getString(mWXComponent.getStyles().getBackgroundColor(), null), 0);
+                    int toColor = WXResourceUtils.getColor(WXUtils.getString(value, null), 0);
+                    if(WXViewUtils.getBorderDrawable(taregtView) != null){
+                        fromColor = WXViewUtils.getBorderDrawable(taregtView).getColor();
+                    }else if (taregtView.getBackground() instanceof ColorDrawable) {
+                        fromColor = ((ColorDrawable) taregtView.getBackground()).getColor();
+                    }
+                    holders.add(PropertyValuesHolder.ofObject(new BackgroundColorProperty(), new ArgbEvaluator(), fromColor,toColor));
+                }
+                break;
+                default:break;
+            }
+        }
+
+        if(token == lockToken.get()) {
+            transformPendingUpdates.clear();
+        }
+        transformAnimator =  ObjectAnimator.ofPropertyValuesHolder(taregtView, holders.toArray(new PropertyValuesHolder[holders.size()]));
+        transformAnimator.setDuration((long) duration);
+        if((long) delay > 0) {
+            transformAnimator.setStartDelay((long) delay);
+        }
+        if(interpolator != null) {
+            transformAnimator.setInterpolator(interpolator);
+        }
+        transformAnimator.addListener(new AnimatorListenerAdapter() {
+            boolean  hasCancel = false;
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                super.onAnimationCancel(animation);
+                hasCancel = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if(hasCancel){
+                    return;
+                }
+                super.onAnimationEnd(animation);
+                WXTransition.this.onTransitionAnimationEnd();
+            }
+        });
+        transformAnimator.start();
+    }
+
+
+    public void doPendingLayoutAnimation(){
+        if(layoutValueAnimator != null){
+            layoutValueAnimator.cancel();
+            layoutValueAnimator = null;
+        }
+        if(layoutPendingUpdates.size() == 0){
+            return;
+        }
+        PropertyValuesHolder[] holders = new PropertyValuesHolder[layoutPendingUpdates.size()];
+        int index = 0;
+        for(String property : properties){
+            if(!LAYOUT_PROPERTIES.contains(property)){
+                continue;
+            }
+            if(layoutPendingUpdates.containsKey(property)){
+                Object targetValue = layoutPendingUpdates.remove(property);
+                synchronized (targetStyles) {
+                    targetStyles.put(property, targetValue);
+                }
+                holders[index] = createLayoutPropertyValueHolder(property, targetValue);
+                index++;
+            }
+        }
+        layoutPendingUpdates.clear();
+        doLayoutPropertyValuesHolderAnimation(holders);
+    }
+
+
+    private PropertyValuesHolder createLayoutPropertyValueHolder(String property, Object value){
+        PropertyValuesHolder holder = null;
+        switch (property){
+            case Constants.Name.WIDTH:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.WIDTH, mWXComponent.getLayoutWidth(),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloat(value, 0.0f), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.HEIGHT:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.HEIGHT, mWXComponent.getLayoutHeight(),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloat(value, 0.0f), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.MARGIN_TOP:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_TOP,  mWXComponent.getMargin().get(
+                    CSSShorthand.EDGE.TOP),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.MARGIN_LEFT:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_LEFT,  mWXComponent.getMargin().get(CSSShorthand.EDGE.LEFT),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.MARGIN_RIGHT:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_RIGHT,  mWXComponent.getMargin().get(CSSShorthand.EDGE.RIGHT),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.MARGIN_BOTTOM:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.MARGIN_BOTTOM,  mWXComponent.getMargin().get(CSSShorthand.EDGE.BOTTOM),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.LEFT:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.LEFT,  mWXComponent.getLayoutPosition().getLeft(),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.RIGHT:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.RIGHT,  mWXComponent.getLayoutPosition().getRight(),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.BOTTOM:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.BOTTOM,  mWXComponent.getLayoutPosition().getBottom(),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.TOP:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.TOP,  mWXComponent.getLayoutPosition().getTop(),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.PADDING_TOP:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_TOP,  mWXComponent.getPadding().get(CSSShorthand.EDGE.TOP),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.PADDING_BOTTOM:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_BOTTOM,  mWXComponent.getPadding().get(CSSShorthand.EDGE.BOTTOM),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.PADDING_LEFT:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_LEFT,  mWXComponent.getPadding().get(CSSShorthand.EDGE.LEFT),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            case Constants.Name.PADDING_RIGHT:{
+                holder = PropertyValuesHolder.ofFloat(Constants.Name.PADDING_RIGHT,  mWXComponent.getPadding().get(CSSShorthand.EDGE.RIGHT),
+                        WXViewUtils.getRealPxByWidth(WXUtils.getFloatByViewport(value, mWXComponent.getViewPortWidth()), mWXComponent.getViewPortWidth()));
+            }
+            break;
+            default:
+                break;
+        }
+        if(holder == null){
+            holder  = PropertyValuesHolder.ofFloat(property, 1, 1);
+        }
+        return  holder;
+    }
+
+    private void doLayoutPropertyValuesHolderAnimation(PropertyValuesHolder[] holders){
+        layoutValueAnimator = ValueAnimator.ofPropertyValuesHolder(holders);
+        layoutValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(final ValueAnimator animation) {
+                PropertyValuesHolder holders[] = animation.getValues();
+                for(PropertyValuesHolder holder : holders){
+
+                    final String property =  holder.getPropertyName();
+                    asynchronouslyUpdateLayout(mWXComponent, property, (Float) animation.getAnimatedValue(property));
+                }
+//                WXBridgeManager.getInstance().calculateLayoutPostToJSThread(mWXComponent.getInstanceId(), mWXComponent.getRef(), false);
+            }
+        });
+        layoutValueAnimator.addListener(new AnimatorListenerAdapter() {
+
+            boolean  hasCancel = false;
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                super.onAnimationCancel(animation);
+                hasCancel = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if(hasCancel){
+                    return;
+                }
+                super.onAnimationEnd(animation);
+                WXTransition.this.onTransitionAnimationEnd();
+            }
+        });
+        if(interpolator != null) {
+            layoutValueAnimator.setInterpolator(interpolator);
+        }
+        layoutValueAnimator.setStartDelay((long) (delay));
+        layoutValueAnimator.setDuration((long) (duration));
+        layoutValueAnimator.start();
+    }
+
+    @SuppressWarnings("unused")
+    public static void asynchronouslyUpdateLayout(WXComponent component, final String propertyName, final float propertyValue) {
+        if(component == null) {
+            return;
+        }
+        final String ref = component.getRef();
+        final String instanceId = component.getInstanceId();
+        if(TextUtils.isEmpty(ref) || TextUtils.isEmpty(instanceId)) {
+            return;
+        }
+
+        WXSDKManager.getInstance().getWXBridgeManager().post(new Runnable() {
+            @Override
+            public void run() {
+                switch (propertyName){
+                    case Constants.Name.WIDTH:{
+                        WXBridgeManager.getInstance().setStyleWidth(instanceId, ref, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.HEIGHT:{
+                        WXBridgeManager.getInstance().setStyleHeight(instanceId, ref, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.MARGIN_TOP:{
+                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.TOP, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.MARGIN_LEFT:{
+                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.LEFT, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.MARGIN_RIGHT:{
+                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.RIGHT, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.MARGIN_BOTTOM:{
+                        WXBridgeManager.getInstance().setMargin(instanceId, ref, CSSShorthand.EDGE.BOTTOM, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.LEFT:{
+                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.LEFT, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.RIGHT:{
+                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.RIGHT, (propertyValue));
+                    }
+                    break;
+                    case Constants.Name.BOTTOM:{
+                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.BOTTOM, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.TOP:{
+                        WXBridgeManager.getInstance().setPosition(instanceId, ref, CSSShorthand.EDGE.TOP, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.PADDING_TOP:{
+                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.TOP, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.PADDING_BOTTOM:{
+                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.BOTTOM, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.PADDING_LEFT:{
+                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.LEFT, propertyValue);
+                    }
+                    break;
+                    case Constants.Name.PADDING_RIGHT:{
+                        WXBridgeManager.getInstance().setPadding(instanceId, ref, CSSShorthand.EDGE.RIGHT, propertyValue);
+                    }
+                    break;
+                    default:
+                        break;
+                }
+            }
+        });
+    }
+
+    private synchronized void onTransitionAnimationEnd(){
+        if(duration > 0){
+            if(transitionEndEvent != null){
+                View view = getTargetView();
+                if(view != null &&  transitionEndEvent != null){
+                    view.post(transitionEndEvent);
+                }
+                transitionEndEvent = null;
+            }
+        }
+        synchronized (targetStyles){
+            if(targetStyles.size() > 0){
+                for(String property : properties) {
+                    if(targetStyles.containsKey(property)){
+                        Object targetValue = targetStyles.remove(property);
+                        mWXComponent.getStyles().put(property, targetValue);
+                    }
+                }
+                targetStyles.clear();
+            }
+        }
+    }
+
+    private View getTargetView(){
+        return null != mWXComponent ? mWXComponent.getHostView() : null;
+    }
+
+
+    /**
+     * get time millis
+     * */
+    private static long parseTimeMillis(Map<String, Object> style, String key, long defaultValue){
+        String  duration = WXUtils.getString(style.get(key), null);
+        if(duration != null){
+            duration = duration.replaceAll("ms", "");
+        }
+        if(duration != null){
+            if(WXEnvironment.isApkDebugable()){
+                if(duration.contains("px")){
+                    WXLogUtils.w("Transition Duration Unit Only Support ms, " + duration + " is not ms Unit");
+                }
+            }
+            duration = duration.replaceAll("px", "");
+        }
+        if(TextUtils.isEmpty(duration)){
+            return  defaultValue;
+        }
+        try{
+            return (long)Float.parseFloat(duration);
+        }catch (NumberFormatException e){
+            return  defaultValue;
+        }
+    }
+
+    /**
+     * create interpolcator same with web
+     * http://www.w3school.com.cn/cssref/pr_transition-timing-function.asp
+     * */
+    private static Interpolator createTimeInterpolator(String interpolator) {
+        if (!TextUtils.isEmpty(interpolator)) {
+            switch (interpolator) {
+                case TimeFunction.EASE_IN:
+                    return PathInterpolatorCompat.create(0.42f,0f, 1f,1f);
+                case TimeFunction.EASE_OUT:
+                    return PathInterpolatorCompat.create(0f,0f, 0.58f,1f);
+                case TimeFunction.EASE_IN_OUT:
+                    return PathInterpolatorCompat.create(0.42f,0f, 0.58f,1f);
+                case TimeFunction.EASE:
+                    return PathInterpolatorCompat.create(0.25f,0.1f, 0.25f,1f);
+                case TimeFunction.LINEAR:
+                    return PathInterpolatorCompat.create(0.0f,0f, 1f,1f);
+                default:
+                    try {
+                        //Parse cubic-bezier
+                        SingleFunctionParser<Float> parser = new SingleFunctionParser<>(
+                                interpolator,
+                                new SingleFunctionParser.FlatMapper<Float>() {
+                                    @Override
+                                    public Float map(String raw) {
+                                        return Float.parseFloat(raw);
+                                    }
+                                });
+                        List<Float> params = parser.parse(TimeFunction.CUBIC_BEZIER);
+                        if (params != null && params.size() == 4) {
+                            return PathInterpolatorCompat.create(
+                                    params.get(0), params.get(1), params.get(2), params.get(3));
+                        }
+                    } catch (RuntimeException e) {
+                        if(WXEnvironment.isApkDebugable()) {
+                            WXLogUtils.e("WXTransition", e);
+                        }
+                    }
+            }
+        }
+        return PathInterpolatorCompat.create(0.25f,0.1f, 0.25f,1f);
+    }
+
+    private static  void  updateTransitionProperties(WXTransition transition, String transtionProperty){
+        if(transtionProperty == null){
+            return;
+        }
+        transition.properties.clear();
+        String[] propertiesArray = PROPERTY_SPLIT_PATTERN.split(transtionProperty);
+        for(String property : propertiesArray){
+            String trim = property.trim();
+            if(TextUtils.isEmpty(trim)){
+                continue;
+            }
+            if(!(LAYOUT_PROPERTIES.contains(trim) || TRANSFORM_PROPERTIES.contains(trim))){
+                if(WXEnvironment.isApkDebugable()){
+                    WXLogUtils.e("WXTransition Property Not Supported" + trim + " in " + transtionProperty);
+                }
+                continue;
+            }
+            transition.properties.add(trim);
+        }
+    }
+
+    public List<String> getProperties() {
+        return properties;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/el/parse/ArrayStack.java b/android/sdk/src/main/java/org/apache/weex/el/parse/ArrayStack.java
new file mode 100644
index 0000000..b492d53
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/el/parse/ArrayStack.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.el.parse;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * stack for parse and execute code
+ * Created by jianbai.gbj on 2017/9/1.
+ */
+public class ArrayStack<T> {
+
+    private ArrayList<T> stack;
+
+    public ArrayStack() {
+        this.stack = new ArrayList<T>(4);
+    }
+
+    public int size() {
+        return stack.size();
+    }
+
+    public T pop() {
+        return stack.remove(stack.size()-1);
+    }
+
+    public void push(T token) {
+        stack.add(token);
+    }
+
+
+    public T peek() {
+        return stack.get(stack.size()-1);
+    }
+
+    public T get(int i) {
+        return stack.get(i);
+    }
+
+    public T remove(int i) {
+        return stack.remove(i);
+    }
+
+    public void add(int i, T t) {
+        stack.add(i, t);
+    }
+
+    public boolean isEmpty() {
+        return   stack.isEmpty();
+    }
+
+    public List<T> getList(){
+        return stack;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/el/parse/Block.java b/android/sdk/src/main/java/org/apache/weex/el/parse/Block.java
new file mode 100644
index 0000000..d593a01
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/el/parse/Block.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.el.parse;
+
+import com.alibaba.fastjson.JSONArray;
+
+import java.util.List;
+
+/**
+ * block, has more than one tokens, but only first will be execute.
+ * Created by jianbai.gbj on 2017/8/28.
+ */
+class Block extends Token {
+    private List<Token> tokens;
+    public Block(List<Token> tokens,  int type) {
+        super("", type);
+        this.tokens = tokens;
+    }
+
+    @Override
+    public Object execute(Object context){
+        if(getType() == TYPE_ARRAY){
+            if(tokens == null || tokens.size() == 0){
+                return  new JSONArray(4);
+            }
+            JSONArray arrayList = new JSONArray(tokens.size());
+            for(int i=0; i<tokens.size(); i++){
+                Token token = tokens.get(i);
+                if(token == null){
+                    arrayList.add(null);
+                }else{
+                    arrayList.add(token.execute(context));
+                }
+            }
+            return arrayList;
+        }
+        if(tokens == null || tokens.size() == 0){
+            return  null;
+        }
+        Token token = tokens.get(0);
+        return token.execute(context);
+    }
+
+    @Override
+    public String toString() {
+        if(getType() == TYPE_ARRAY){
+            return "" + tokens + "";
+        }else {
+            if(tokens != null && tokens.size() == 1){
+                return "{" + tokens.get(0) + '}';
+            }
+            return "{" + tokens + '}';
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/el/parse/Operator.java b/android/sdk/src/main/java/org/apache/weex/el/parse/Operator.java
new file mode 100644
index 0000000..839d541
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/el/parse/Operator.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.el.parse;
+
+
+/**
+ * Created by jianbai.gbj on 2017/8/28.
+ * one operator, two operator, and three operator
+ */
+class Operator extends Token {
+    public Token self;
+    public Token first;
+    public Token second;
+
+    public Operator(String operator, int type) {
+        super(operator, type);
+    }
+
+
+    @Override
+    public Object execute(Object context){
+        String op = getToken();
+        switch (op){
+            case  Operators.DOT_STR:
+            case  Operators.ARRAY_START_STR:{
+                return  Operators.dot(first, second, context);
+            }
+            case  Operators.EQUAL:
+            case  Operators.EQUAL2:{
+                return Operators.isEquals(first, second, context);
+            }
+            case  Operators.NOT_EQUAL:
+            case  Operators.NOT_EQUAL2:{
+                return !Operators.isEquals(first, second, context);
+            }
+            case  Operators.CONDITION_IF_STRING:{
+                return Operators.condition(self, first, second, context);
+            }
+            case  Operators.AND_NOT:{
+                return  !Operators.tokenTrue(self, context);
+            }
+            case  Operators.AND:{
+                return  Operators.tokenTrue(first, context) && Operators.tokenTrue(second, context);
+            }
+            case  Operators.OR:{
+                return  Operators.tokenTrue(first, context) || Operators.tokenTrue(second, context);
+            }
+            case  Operators.G:{
+                return  Operators.tokenNumber(first, context) > Operators.tokenNumber(second, context);
+            }
+            case  Operators.GE:{
+                return  Operators.tokenNumber(first, context) >= Operators.tokenNumber(second, context);
+            }
+            case  Operators.L:{
+                return  Operators.tokenNumber(first, context) < Operators.tokenNumber(second, context);
+            }
+            case  Operators.LE:{
+                return  Operators.tokenNumber(first, context) <= Operators.tokenNumber(second, context);
+            }
+            case  Operators.PLUS:{
+                return  Operators.plus(first, second, context);
+            }
+            case  Operators.SUB:{
+                return  Operators.sub(first, second, context);
+            }
+            case  Operators.MUL:{
+                return  Operators.mul(first, second, context);
+            }
+            case  Operators.DIV:{
+                return  Operators.div(first, second, context);
+            }
+            case  Operators.MOD:{
+                return  Operators.mod(first, second, context);
+            }
+            default:
+                throw new IllegalArgumentException(op + " operator is not supported");
+        }
+    }
+
+    @Override
+    public String toString() {
+        if(Operators.AND_NOT.equals(getToken())){
+            return "{!" +  self + "}";
+        }
+        if(self == null){
+            return "{" + first +  getToken() + second + "}";
+        }
+        return "{" + self + getToken() + first + ":" + second + "}";
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/el/parse/Operators.java b/android/sdk/src/main/java/org/apache/weex/el/parse/Operators.java
new file mode 100644
index 0000000..61d1842
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/el/parse/Operators.java
@@ -0,0 +1,502 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.el.parse;
+
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Created by furture on 2017/8/28.
+ */
+public class Operators {
+
+
+    public static Object dot(Token left, Token right, Object context){
+        if(left == null || right == null){
+            return null;
+        }
+        Object leftValue = left.execute(context);
+        if(leftValue == null){
+            return null;
+        }
+        Object value =  null;
+        if(right.getType() != Token.TYPE_IDENTIFIER){
+            Object identifter = right.execute(context);
+            if(identifter instanceof Double){
+                identifter = ((Double) identifter).intValue();
+            }
+            String key = identifter == null ? "" : identifter.toString().trim();
+            value = Operators.el(leftValue, key);
+        }else{
+            value = right.execute(leftValue);
+        }
+        if(value != null){
+            return value;
+        }
+        return  specialKey(leftValue, right.getToken());
+    }
+
+    /**
+     * get key's value on object
+     * */
+    public static  Object el(Object context, String key){
+        if(context == null){
+            return  null;
+        }
+        // TODO
+//        if(context instanceof CellRenderContext){
+//            if(WXEnvironment.isApkDebugable()){
+//                throw new IllegalArgumentException("rong context CellRenderContext, you should pass it's stack");
+//            }
+//            context = ((CellRenderContext) context).stack;
+//        }
+        if(context instanceof ArrayStack){
+            ArrayStack stack = (ArrayStack) context;
+            for(int index=stack.size()-1; index >= 0; index--){
+                Object value = stack.get(index);
+                if(value instanceof  Map){
+                    Map map = (Map) value;
+                    if(map.containsKey(key)){
+                        return map.get(key);
+                    }
+                }
+            }
+        }
+        if(context instanceof Stack){
+            Stack stack = (Stack) context;
+            for(int index=stack.size()-1; index >= 0; index--){
+                Object value = stack.get(index);
+                if(value instanceof  Map){
+                    Map map = (Map) value;
+                    if(map.containsKey(key)){
+                        return map.get(key);
+                    }
+                }
+            }
+        }
+
+        if(context instanceof  Map){
+            return ((Map) context).get(key);
+        }
+
+        if(context instanceof List){
+            List list = (List) context;
+            try{
+                return list.get(Integer.parseInt(key));
+            }catch (Exception e){}
+        }
+        if(context.getClass().isArray()){
+            try{
+                return Array.get(context, Integer.parseInt(key));
+            }catch (Exception e){}
+        }
+        return  null;
+    }
+
+    public static  Object specialKey(Object leftValue, String key){
+        if("length".equals(key)){
+            if(leftValue instanceof  CharSequence){
+                return ((CharSequence) leftValue).length();
+            }
+            if(leftValue instanceof  Map){
+                return  ((Map) leftValue).size();
+            }
+            if(leftValue instanceof  Map){
+                return  ((Map) leftValue).size();
+            }
+            if(leftValue instanceof  List){
+                return  ((List) leftValue).size();
+            }
+            if(leftValue.getClass().isArray()){
+                return Array.getLength(leftValue);
+            }
+        }
+        return null;
+    }
+
+    public static Object plus(Token left, Token right, Object context){
+        Object leftValue = null;
+        Object rightValue = null;
+        if(left != null){
+            leftValue = left.execute(context);
+        }
+        if(right  != null){
+            rightValue = right.execute(context);
+        }
+        if(leftValue instanceof  CharSequence || rightValue instanceof  CharSequence){
+            if(leftValue == null){
+                return  rightValue;
+            }
+            return leftValue.toString() + (rightValue == null ? "" : rightValue.toString());
+        }
+        if(leftValue instanceof  Number || rightValue instanceof Number){
+            return getNumber(leftValue) + getNumber(rightValue);
+        }
+        if(leftValue == null && rightValue == null){
+            return  null;
+        }
+        if(leftValue == null){
+            return  rightValue.toString();
+        }
+        return leftValue.toString() + (rightValue == null ? "" : rightValue.toString());
+    }
+
+
+    public static Object sub(Token left, Token right, Object context){
+        Object leftValue = null;
+        Object rightValue = null;
+        if(left != null){
+            leftValue = left.execute(context);
+        }
+        if(right  != null){
+            rightValue = right.execute(context);
+        }
+        return getNumber(leftValue) - getNumber(rightValue);
+    }
+
+    public static Object div(Token left, Token right, Object context){
+        Object leftValue = null;
+        Object rightValue = null;
+        if(left != null){
+            leftValue = left.execute(context);
+        }
+        if(right  != null){
+            rightValue = right.execute(context);
+        }
+        return getNumber(leftValue)/getNumber(rightValue);
+    }
+
+    public static Object mul(Token left, Token right, Object context){
+        Object leftValue = null;
+        Object rightValue = null;
+        if(left != null){
+            leftValue = left.execute(context);
+        }
+        if(right  != null){
+            rightValue = right.execute(context);
+        }
+        return getNumber(leftValue)*getNumber(rightValue);
+    }
+
+    public static Object mod(Token left, Token right, Object context){
+        Object leftValue = null;
+        Object rightValue = null;
+        if(left != null){
+            leftValue = left.execute(context);
+        }
+        if(right  != null){
+            rightValue = right.execute(context);
+        }
+        return (getNumber(leftValue))%(getNumber(rightValue));
+    }
+
+    /**
+     * condition expression
+     * */
+    public static Object condition(Token selfs, Token first, Token second, Object context){
+        boolean value = false;
+        if(selfs != null){
+            value = isTrue(selfs.execute(context));
+        }
+        if(value){
+            if(first != null){
+                return  first.execute(context);
+            }
+        }else{
+            if(second != null){
+                return  second.execute(context);
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * is token value is true
+     * */
+    public static boolean tokenTrue(Token selfs, Object context) {
+        if(selfs == null){
+            return false;
+        }
+        Object value = selfs.execute(context);
+        return  isTrue(value);
+    }
+
+    /**
+     * get token number
+     * */
+    public static double tokenNumber(Token self,  Object context) {
+        if(self == null){
+            return  0;
+        }
+        Object value = self.execute(context);
+        return  getNumber(value);
+    }
+
+
+
+    /**
+     * isEquls operation
+     * */
+    public static boolean isEquals(Token left, Token right, Object context){
+        if(left == null && right == null){
+            return  true;
+        }
+        Object leftValue =  null;
+        if(left != null){
+            leftValue  = left.execute(context);
+        }
+        Object rightValue = null;
+        if(right != null) {
+            rightValue = right.execute(context);
+        }
+        if(leftValue == null){
+            if(rightValue == null){
+                return  true;
+            }
+            if(rightValue instanceof  CharSequence){
+                if(isEmpty(rightValue.toString())){
+                    return  true;
+                }
+            }
+            return  false;
+        }
+        if(rightValue == null){
+            if(isEmpty(leftValue.toString())){
+                return  true;
+            }
+            return  false;
+        }
+        if(leftValue instanceof  Number){
+            if(rightValue instanceof  Number){
+                return  ((Number) leftValue).doubleValue() == ((Number) rightValue).doubleValue();
+            }
+            return ((Number) leftValue).doubleValue() == getNumber(rightValue);
+        }
+        if(rightValue instanceof  Number){
+            return getNumber(leftValue) == ((Number) rightValue).doubleValue();
+        }
+        if(leftValue instanceof CharSequence
+                ||  rightValue instanceof CharSequence){
+            return  leftValue.toString().trim().equals(rightValue.toString().trim());
+        }
+        return  leftValue.equals(rightValue);
+    }
+
+
+    /**
+     * check whether value is true
+     * */
+    public static boolean isTrue(Object value){
+        if(value == null){
+            return  false;
+        }
+        if(value instanceof  Number){
+            return ((Number) value).doubleValue() != 0;
+        }
+        String bool = value.toString().trim();
+        if("false".equals(bool)
+                || "undefined".equals(bool)
+                || "null".equals(bool)){
+            return  false;
+        }
+        if(isEmpty(bool)){
+            return  false;
+        }
+        return  true;
+    }
+
+    /**
+     * check String value is empty
+     * */
+    public static boolean isEmpty(String value){
+        if (value == null){
+            return  true;
+        }
+        for(int i=0; i<value.length(); i++){
+            if(value.charAt(i) != ' '){
+                return  false;
+            }
+        }
+        return true;
+    }
+
+
+    /**
+     * get number
+     * */
+    public static double getNumber(Object value){
+        if(value == null){
+            return  0;
+        }
+        if(value instanceof  Number){
+            return  ((Number) value).doubleValue();
+        }
+        try{
+            return Double.parseDouble(value.toString());
+        }catch (Exception e){return  0;}
+    }
+
+    public static boolean isOpEnd(String op){
+        return isOpEnd(op.charAt(0));
+    }
+    /**
+     * op end, has none operation, should not enter operator stack.
+     * */
+    public static boolean isOpEnd(char op){
+        if(op == BRACKET_END
+                || op == ARRAY_END
+                || op == SPACE
+                || op == ARRAY_SEPRATOR){
+            return true;
+        }
+        return  false;
+    }
+
+    /**
+     * is not
+     * */
+    public static boolean isDot(String opStr){
+        char op = opStr.charAt(0);
+        return  op == DOT || op == ARRAY_START;
+    }
+
+
+
+
+    public static final char BRACKET_END = ')';
+    public static final String BRACKET_END_STR = ")";
+    public static final char BRACKET_START = '(';
+    public static final String BRACKET_START_STR = "(";
+    public static final char QUOTE = '"';
+    public static final char SINGLE_QUOTE = '\'';
+    public static final char DOT = '.';
+    public static final String DOT_STR = ".";
+    public static final char ARRAY_START = '[';
+    public static final String ARRAY_START_STR = "[";
+    public static final char ARRAY_SEPRATOR = ',';
+    public static final String ARRAY_SEPRATOR_STR = ",";
+    public static final char ARRAY_END = ']';
+    public static final String ARRAY_END_STR = "]";
+    public static final String SPACE_STR = " ";
+    public static final char SPACE = ' ';
+    public static final char BLOCK_START = '{';
+    public static final String BLOCK_START_STR = "{";
+    public static final char BLOCK_END = '}';
+    public static final String BLOCK_END_STR = "}";
+    public static final char DOLLAR = '$';
+    public static final String DOLLAR_STR = "$";
+
+    /**
+     * condition
+     * */
+    public static final char  CONDITION_IF = '?';
+    public static final String  CONDITION_IF_STRING = "?";
+    public static final char  CONDITION_IF_MIDDLE = ':';
+
+
+
+    /**
+     * match
+     * */
+    public static final String PLUS ="+";
+    public static final String SUB = "-";
+    public static final String MUL = "*";
+    public static final String DIV = "/";
+    public static final String MOD = "%";
+
+
+
+    public static final String AND  = "&&";
+    public static final String OR  = "||";
+    /**
+     * and operator
+     * */
+    public static final String EQUAL = "===";
+    public static final String EQUAL2 = "==";
+    public static final String NOT_EQUAL = "!==";
+    public static final String NOT_EQUAL2 = "!=";
+    public static final String AND_NOT = "!";
+
+
+    public static final String G = ">";
+    public static final String GE = ">=";
+    public static final String LE = "<=";
+    public static final String L = "<";
+
+
+
+
+
+    /**
+     * https://github.com/jquery/esprima/blob/master/src/parser.ts
+     * */
+    public static Map<String, Integer> OPERATORS_PRIORITY = new HashMap<>();
+    static {
+        OPERATORS_PRIORITY.put(BLOCK_END_STR, 0);
+        OPERATORS_PRIORITY.put(BRACKET_END_STR, 0);
+        OPERATORS_PRIORITY.put(SPACE_STR, 0);
+        OPERATORS_PRIORITY.put(ARRAY_SEPRATOR_STR, 0);
+        OPERATORS_PRIORITY.put(ARRAY_END_STR, 0);
+
+
+        OPERATORS_PRIORITY.put(OR, 1);
+        OPERATORS_PRIORITY.put(AND, 1);
+
+        OPERATORS_PRIORITY.put(EQUAL, 2);
+        OPERATORS_PRIORITY.put(EQUAL2, 2);
+        OPERATORS_PRIORITY.put(NOT_EQUAL, 2);
+        OPERATORS_PRIORITY.put(NOT_EQUAL2, 2);
+
+        OPERATORS_PRIORITY.put(G, 7);
+        OPERATORS_PRIORITY.put(GE, 7);
+        OPERATORS_PRIORITY.put(L, 7);
+        OPERATORS_PRIORITY.put(LE, 8);
+
+        OPERATORS_PRIORITY.put(PLUS, 9);
+        OPERATORS_PRIORITY.put(SUB, 9);
+        OPERATORS_PRIORITY.put(MUL, 10);
+        OPERATORS_PRIORITY.put(DIV, 10);
+        OPERATORS_PRIORITY.put(MOD, 10);
+        OPERATORS_PRIORITY.put(AND_NOT, 11);
+
+        OPERATORS_PRIORITY.put(DOT_STR, 15);
+        
+        OPERATORS_PRIORITY.put(ARRAY_START_STR, 16);
+
+
+        OPERATORS_PRIORITY.put(BRACKET_START_STR, 17);
+        OPERATORS_PRIORITY.put(BLOCK_START_STR, 17);
+
+
+    }
+
+
+    public static final Map<String,Object> KEYWORDS = new HashMap<>();
+    static {
+        KEYWORDS.put("null", null);
+        KEYWORDS.put("true", Boolean.TRUE);
+        KEYWORDS.put("false", Boolean.FALSE);
+        KEYWORDS.put("undefined", null);
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/el/parse/Parser.java b/android/sdk/src/main/java/org/apache/weex/el/parse/Parser.java
new file mode 100644
index 0000000..ea85032
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/el/parse/Parser.java
@@ -0,0 +1,486 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.el.parse;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Created by furture on 2017/8/28.
+ * simple expression parse, less ast node and save memory
+ */
+public class Parser {
+
+    private String code;
+    private int position;
+    private ArrayStack<Token> stacks;
+    private ArrayStack<Symbol> operators;
+
+    public Parser(String code){
+        this.code = code;
+        this.position = 0;
+        this.stacks = new ArrayStack<>();
+        this.operators = new ArrayStack<>();
+    }
+
+
+    public final Token parse(){
+        while (hasNextToken()){
+            scanNextToken();
+        }
+        while (!operators.isEmpty()){
+            Symbol op = operators.pop();
+            doOperator(op);
+        }
+        if(stacks.size() == 1){
+            return  stacks.pop();
+        }
+        Block block = new Block(stacks.getList(), Token.TYPE_BLOCK);
+        return block;
+    }
+
+
+    /**
+     * parse code to ast block.
+     * */
+    public static Token parse(String code){
+        try{
+            Parser parser = new Parser(code);
+            return parser.parse();
+        }catch (Exception e){
+            if(WXEnvironment.isApkDebugable()){
+                WXLogUtils.e("code " + code, e);
+            }
+            return new Block(null, Token.TYPE_BLOCK);
+        }
+    }
+
+
+    final char scanNextToken(){
+        char ch = nextToken();
+        if(ch == Operators.DOLLAR){
+            position++;
+            return ch;
+        }else if(Character.isJavaIdentifierStart(ch)){
+            scanIdentifier();
+        }else if (ch == Operators.BRACKET_START || ch == Operators.BLOCK_START) {
+            scanBracket();
+        }else if (ch == Operators.ARRAY_START) {
+            scanArray();
+        }else if (ch ==  Operators.QUOTE || ch == Operators.SINGLE_QUOTE) {
+            scanString();
+        }else if((ch == Operators.DOT && Character.isDigit(code.charAt(position + 1)))
+                || Character.isDigit(ch)){ //number .00 .00e6
+            scanNumber();
+        }else if(ch ==  Operators.CONDITION_IF){
+            scanIf();
+        }else if(ch ==  Operators.CONDITION_IF_MIDDLE
+                || ch ==  Operators.BRACKET_END
+                || ch == Operators.BLOCK_END
+                || ch == Operators.SPACE
+                || ch == Operators.ARRAY_END){
+            position++;
+            return ch;
+        }else{
+            scanOperator();
+        }
+        return ch;
+    }
+
+
+    final void  scanArray(){
+        int stackSize = stacks.size();
+        int opSize = operators.size();
+        int type = Token.TYPE_IDENTIFIER;
+        if(position - 1 < 0 || !Character.isJavaIdentifierPart(code.charAt(position - 1))){
+            type = Token.TYPE_ARRAY;
+        }
+        operators.push(new Symbol(Operators.ARRAY_START_STR, stacks.size()));
+        position++;
+        while (hasNextToken()){
+            char token = scanNextToken();
+            if(token == Operators.ARRAY_END){
+                break;
+            }
+        }
+
+        if(stacks.size() <= stackSize){ // empty bracket, none need, save memory
+            while (operators.size() > opSize){
+                operators.pop();
+            }
+            return;
+        }
+
+        while (operators.size() > opSize){
+            Symbol op = operators.pop();
+            if(stacks.size() > stackSize){
+                doOperator(op);
+            }
+        }
+        List<Token> tokens = new ArrayList<>(4);
+        for(int i=stackSize; i<stacks.size(); i++){
+            tokens.add(stacks.get(i));
+        }
+        while (stacks.size() > stackSize){
+            stacks.pop();
+        }
+        if(type == Token.TYPE_ARRAY || stacks.size() == 0){
+            Block block = new Block(tokens, Token.TYPE_ARRAY);
+            stacks.push(block);
+            return;
+        }
+
+        Token identifer = stacks.pop();
+        Token second = null;
+        if(tokens.size() == 1){
+            second = tokens.get(0);
+        }else{
+            second = new Block(tokens, Token.TYPE_BLOCK);
+        }
+        Operator operator = new Operator(Operators.DOT_STR, type);
+        operator.first = identifer;
+        operator.second = second;
+        stacks.push(operator);
+    }
+
+    void  scanBracket(){
+        int stackSize = stacks.size();
+        int opSize = operators.size();
+        if(code.charAt(position) == Operators.BLOCK_START){
+            operators.push(new Symbol(Operators.BLOCK_START_STR, stacks.size()));
+            position++;
+            while (hasNextToken()){
+                if(scanNextToken() == Operators.BLOCK_END){
+                    break;
+                }
+            }
+        }else{
+            operators.push(new Symbol(Operators.BRACKET_START_STR, stacks.size()));
+            position++;
+            while (hasNextToken()){
+                if(scanNextToken() == Operators.BRACKET_END){
+                    break;
+                }
+            }
+        }
+        if(stacks.size() <= stackSize){ // empty bracket, none need, save memory
+            while (operators.size() > opSize){
+                operators.pop();
+            }
+            return;
+        }
+        while (operators.size() > opSize){
+            Symbol op = operators.pop();
+            if(stacks.size() > stackSize){
+                doOperator(op);
+            }
+        }
+        List<Token> tokens = new ArrayList<>(4);
+        for(int i=stackSize; i<stacks.size(); i++){
+            tokens.add(stacks.get(i));
+        }
+        while (stacks.size() > stackSize){
+            stacks.pop();
+        }
+        if(tokens.size() == 1){
+            stacks.push(tokens.get(0));
+        }else{
+            Block block = new Block(tokens, Token.TYPE_BLOCK);
+            stacks.push(block);
+        }
+    }
+
+    /**
+     * 1  === (1 + 3) &&  1
+     * scan operator
+     * */
+    void scanOperator(){
+        int start = position;
+        int length = Math.min(position + 3, code.length());
+        String operator = code.substring(position, length);
+        if(operator.length() >= 3){
+            if(!Operators.OPERATORS_PRIORITY.containsKey(operator)){
+                operator = operator.substring(0, 2);
+            }
+        }
+        if(operator.length() >= 2){
+            if(!Operators.OPERATORS_PRIORITY.containsKey(operator)){
+                operator = operator.substring(0, 1);
+            }
+        }
+        if(!Operators.OPERATORS_PRIORITY.containsKey(operator)){
+            //just skip illegal character
+            int illegalChar = Math.min(start + 1, code.length());
+            WXLogUtils.e("weex", new IllegalArgumentException(code.substring(0, illegalChar) + " illegal code operator" + operator));
+            position += operator.length();
+            return;
+        }
+        if((!operators.isEmpty() && operators.peek() != null)){
+            String preOp = operators.peek().op;
+            if(Operators.OPERATORS_PRIORITY.get(preOp) >= Operators.OPERATORS_PRIORITY.get(operator)){
+                Symbol op = operators.pop();
+                doOperator(op);
+            }
+        }
+        if(!Operators.isOpEnd(operator)){
+            operators.push(new Symbol(operator, stacks.size()));
+        }
+        position += operator.length();
+    }
+
+
+
+    void doOperator(Symbol symbol){
+        String op = symbol.op;
+        if(Operators.BRACKET_START_STR.equals(symbol.op)
+                || Operators.BLOCK_START_STR.equals(symbol.op)
+                || Operators.ARRAY_START_STR.equals(symbol.op)
+                || Operators.DOLLAR_STR.equals(symbol.op)){
+            return;
+        }
+        if(Operators.BLOCK_START_STR.equals(symbol.op)){
+            return;
+        }
+        int second = symbol.pos;
+        int first  = Math.max(symbol.pos - 1, 0);
+        if(!operators.isEmpty()){
+            first = Math.max(first, operators.peek().pos);
+        }
+
+        Operator operator = new Operator(op, Token.TYPE_OPERATOR);
+        if(Operators.AND_NOT.equals(op)){
+            if(stacks.size() > second) {
+                Token token = stacks.remove(second);
+                operator.self = token;
+                stacks.add(second, operator);
+                return;
+            }
+            return; //invalid
+        }
+        if(stacks.size() > second) {
+            operator.second = stacks.remove(second);
+        }else{
+            return;
+        }
+        if(stacks.size() > first) {
+            operator.first = stacks.remove(first);
+        }else{
+            if(operator.second == null){
+                return;
+            }
+        }
+        stacks.add(first, operator);
+    }
+
+    /**
+     * condition if
+     * */
+    void scanIf(){
+        Operator operator = new Operator(Operators.CONDITION_IF_STRING, Token.TYPE_OPERATOR);
+        int selfIndex = 0;
+        doStackOperators(0);
+        if(operators.size() > 0){
+            selfIndex = Math.max(operators.peek().pos, selfIndex);
+        }
+        if(stacks.size() > selfIndex){
+            operator.self = stacks.pop();
+        }
+
+        int stackSize = stacks.size();
+        int leftOperatorSize = operators.size();
+        position++;
+        while (hasNextToken()){
+            if(scanNextToken() == Operators.CONDITION_IF_MIDDLE){
+                break;
+            }
+        }
+        while (operators.size() > leftOperatorSize){
+            Symbol symbol = operators.pop();
+            doOperator(symbol);
+        }
+
+        while (stacks.size() > stackSize){
+            operator.first = stacks.pop();
+        }
+        int rightOperatorsSize = operators.size();
+        while (hasNextToken()){
+            scanNextToken();
+            if(hasNextToken()){
+                scanNextToken();
+            }
+            if(operators.size() <= rightOperatorsSize){
+                break;
+            }
+        }
+        doStackOperators(rightOperatorsSize);
+        while (stacks.size() > stackSize){
+            operator.second = stacks.pop();
+        }
+        stacks.push(operator);
+    }
+
+    private final void doStackOperators(int operatorSize){
+        while (operators.size() > operatorSize){
+            Symbol symbol = operators.pop();
+            doOperator(symbol);
+        }
+    }
+
+    /**
+     * 1+e6
+     * .00
+     * .00e6
+     * 100
+     * 199e5
+     * */
+    final void scanNumber(){
+        boolean isInt = true;
+        int start = position;
+        if(code.charAt(position) == 'e' || code.charAt(position) == '.'){
+            isInt = false;
+        }
+        position++;
+        while (hasNext()){
+            char ch = code.charAt(position);
+            if(Character.isDigit(ch)
+                    || ch == '.'
+                    || ch =='e'){
+                if(ch == 'e'
+                        || ch == '.'){
+                    isInt = false;
+                }
+                position++;
+            }else{
+                break;
+            }
+        }
+        String number = code.substring(start, position);
+        if(".".equals(number)){
+            return;
+        }
+        Token stack = null;
+        if(isInt){
+            stack = new Token(number, Token.TYPE_INT);
+        }else{
+            stack = new Token(number, Token.TYPE_DOUBLE);
+        }
+        stacks.push(stack);
+    }
+
+
+    final void  scanString(){
+        int start = position;
+        ArrayStack operator = new ArrayStack();
+        char quote = code.charAt(start);
+        operator.push(quote);
+        StringBuilder builder = new StringBuilder();
+        for(position= start + 1; position<code.length(); position++){
+            char ch = code.charAt(position);
+            if(ch == quote){
+                if(code.charAt(position -1) != '\\'){
+                    operator.pop();
+                    if(operator.size() == 0){
+                       position++;
+                       break;
+                    }
+                }else{
+                    builder.deleteCharAt(builder.length()-1);
+                    builder.append(ch);
+                }
+            }else{
+                builder.append(ch);
+            }
+        }
+        String string =  builder.toString();
+        Token token = new Token(string, Token.TYPE_STRING);
+        stacks.push(token);
+    }
+
+
+
+    /**
+     * scan el expression.
+     * item.ddd
+     * ${item.dd}
+     * $item.dd
+     * */
+    final void scanIdentifier(){
+        int start = position;
+        position++;
+        while (hasNext()){
+            char ch = code.charAt(position);
+            if(Character.isJavaIdentifierPart(ch)){
+               position++;
+            }else{
+                break;
+            }
+            //2.true
+        }
+        String el = code.substring(start, position);
+        if(el.startsWith(Operators.DOLLAR_STR)){
+            if(el.length() == Operators.DOLLAR_STR.length()){
+                return;
+            }
+            el = el.substring(Operators.DOLLAR_STR.length());
+        }
+        int type = Token.TYPE_IDENTIFIER;
+        if(Operators.KEYWORDS.containsKey(el)){
+            if(!(!operators.isEmpty() && Operators.isDot(operators.peek().op))){
+                type = Token.TYPE_KEYWORD;
+            }
+        }
+        Token token = new Token(el, type);
+        stacks.push(token);
+    }
+
+
+    final boolean hasNext(){
+        return position < code.length();
+    }
+
+
+
+    final boolean hasNextToken(){
+        while (hasNext()){
+            char ch = code.charAt(position);
+            if(ch == ' '){
+                position++;
+                continue;
+            }
+            return  true;
+        }
+        return false;
+    }
+
+    final char nextToken(){
+        char ch = code.charAt(position);
+        while (ch == ' '){
+            position ++;
+            if(code.length() <= position){
+                break;
+            }
+            ch = code.charAt(position);
+        }
+        return ch;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/el/parse/Symbol.java b/android/sdk/src/main/java/org/apache/weex/el/parse/Symbol.java
new file mode 100644
index 0000000..2136633
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/el/parse/Symbol.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.el.parse;
+
+/**
+ * Created by furture on 2017/8/29.
+ */
+
+public class Symbol {
+    public final String op;
+    public final int pos;
+    public Symbol(String op, int pos) {
+        this.op = op;
+        this.pos = pos;
+    }
+
+    /**
+    @Override
+    public String toString() {
+        return op;
+    }*/
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/el/parse/Token.java b/android/sdk/src/main/java/org/apache/weex/el/parse/Token.java
new file mode 100644
index 0000000..f0d6186
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/el/parse/Token.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.el.parse;
+
+/**
+ * Created by furture on 2017/8/28.
+ */
+public class Token {
+
+    /**
+     * token's type
+     * */
+    public static final int TYPE_IDENTIFIER = 0;
+    public static final int TYPE_INT = 1;
+    public static final int TYPE_DOUBLE = 2;
+    public static final int TYPE_STRING = 3;
+    public static final int TYPE_KEYWORD = 4;
+    public static final int TYPE_OPERATOR = 5;
+    public static final int TYPE_BLOCK = 6;
+
+    public static final int TYPE_ARRAY = 7;
+
+
+
+    private String token;
+    private int type;
+
+    public Token(String token, int type){
+        this.token = token;
+        this.type = type;
+    }
+
+
+    /**
+     * stack should use array stack.
+     * execute token in context, and return value.
+     * */
+    public Object execute(Object context){
+        if(type == TYPE_IDENTIFIER){
+            return Operators.el(context, token);
+        }else if(type == TYPE_STRING){
+            return  token;
+        }else if(type == TYPE_INT){
+            try{
+                return  Integer.parseInt(token);
+            }catch (Exception e){
+                return 0;
+            }
+        }else if(type == TYPE_DOUBLE){
+            try{
+                return  Double.parseDouble(token);
+            }catch (Exception e){
+                return 0;
+            }
+        }else if(type == TYPE_KEYWORD){
+            return  Operators.KEYWORDS.get(token);
+        }
+        throw new IllegalArgumentException("unhandled token type " + type);
+    }
+
+    @Override
+    public String toString() {
+        return "{" + token + "," + type + '}';
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public int getType() {
+        return type;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/font/FontAdapter.java b/android/sdk/src/main/java/org/apache/weex/font/FontAdapter.java
new file mode 100644
index 0000000..9140e60
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/font/FontAdapter.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.font;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class FontAdapter {
+
+
+    private List<FontListener> mFontListener;
+
+    public FontAdapter(){
+        mFontListener = new CopyOnWriteArrayList<>();
+    }
+
+    public void addFontListener(FontListener fontListener){
+        mFontListener.add(fontListener);
+    }
+
+    public void removeFontListener(FontListener fontListener){
+        mFontListener.remove(fontListener);
+    }
+
+    public void onAddFontRule(String pageId, String fontFamily, String fontUrl){
+        synchronized (this){
+            for(FontListener fontListener : mFontListener){
+                fontListener.onAddFontRule(pageId, fontFamily, fontUrl);
+            }
+        }
+    }
+
+    public void onFontLoad(String fontFaimly, String fontUrl, String filePath){
+        synchronized (this) {
+            for (FontListener fontListener : mFontListener) {
+                fontListener.onFontLoad(fontFaimly, fontUrl, filePath);
+            }
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/font/FontListener.java b/android/sdk/src/main/java/org/apache/weex/font/FontListener.java
new file mode 100644
index 0000000..50cd1b9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/font/FontListener.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.font;
+
+public interface FontListener {
+
+    public void onAddFontRule(String pageId, String fontFamily, String fontUrl);
+
+    public void onFontLoad(String fontFamily, String fontUrl, String filePath);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/http/Options.java b/android/sdk/src/main/java/org/apache/weex/http/Options.java
new file mode 100644
index 0000000..9a82f6b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/http/Options.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.http;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.weex.common.*;
+import org.apache.weex.common.WXRequest;
+
+/**
+ * Created by sospartan on 5/19/16.
+ */
+class Options {
+  private String method;
+  private String url;
+  private Map<String, String> headers;
+  private String body;
+  private Type type = Type.text;
+  private int timeout = WXRequest.DEFAULT_TIMEOUT_MS;
+
+  private Options(String method,
+                  String url,
+                  Map<String, String> headers,
+                  String body,
+                  Type type,
+                  int timeout) {
+    this.method = method;
+    this.url = url;
+    this.headers = headers;
+    this.body = body;
+    this.type = type;
+    if (timeout == 0) {
+      timeout = WXRequest.DEFAULT_TIMEOUT_MS;
+    }
+    this.timeout = timeout;
+  }
+
+  public String getMethod() {
+    return method;
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  public Map<String, String> getHeaders() {
+    return headers;
+  }
+
+  public String getBody() {
+    return body;
+  }
+
+  public Type getType() {
+    return type;
+  }
+
+  public int getTimeout() { return timeout; }
+
+  public enum Type {
+    json, text,jsonp
+  }
+
+  public static class Builder {
+    private String method;
+    private String url;
+    private Map<String, String> headers = new HashMap<>();
+    private String body;
+    private Type type;
+    private int timeout;
+
+    public Builder setMethod(String method) {
+      this.method = method;
+      return this;
+    }
+
+    public Builder setUrl(String url) {
+      this.url = url;
+      return this;
+    }
+
+    public Builder putHeader(String key,String value){
+      this.headers.put(key,value);
+      return this;
+    }
+
+    public Builder setBody(String body) {
+      this.body = body;
+      return this;
+    }
+
+    /**
+     * default text
+     * json = jsonp
+     * @param type
+     * @return
+       */
+    public Builder setType(String type) {
+      if(Type.json.name().equals(type)){
+        this.type = Type.json;
+      }else if(Type.jsonp.name().equals(type)){
+        this.type = Type.jsonp;
+      }else{
+        this.type = Type.text;
+      }
+      return this;
+    }
+
+    public Builder setType(Type type) {
+      this.type = type;
+      return this;
+    }
+
+    public Builder setTimeout(int timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public Options createOptions() {
+      return new Options(method, url, headers, body, type, timeout);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/http/Status.java b/android/sdk/src/main/java/org/apache/weex/http/Status.java
new file mode 100644
index 0000000..69b3892
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/http/Status.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.http;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by sospartan on 5/26/16.
+ */
+public class Status {
+  public static final String UNKNOWN_STATUS = "unknown status";
+  public static final String ERR_INVALID_REQUEST = "ERR_INVALID_REQUEST";
+  public static final String ERR_CONNECT_FAILED = "ERR_CONNECT_FAILED";
+
+  private static Map<String,String> statusMap = new HashMap<>();
+
+  static {
+    statusMap.put("100","Continue");
+    statusMap.put("101","Switching Protocol");
+    statusMap.put("200","OK");
+    statusMap.put("201","Created");
+    statusMap.put("202","Accepted");
+    statusMap.put("203","Non-Authoritative Information");
+    statusMap.put("204","No Content");
+    statusMap.put("205","Reset Content");
+    statusMap.put("206","Partial Content");
+    statusMap.put("300","Multiple Choice");
+    statusMap.put("301","Moved Permanently");
+    statusMap.put("302","Found");
+    statusMap.put("303","See Other");
+    statusMap.put("304","Not Modified");
+    statusMap.put("305","Use Proxy");
+    statusMap.put("306","unused");
+    statusMap.put("307","Temporary Redirect");
+    statusMap.put("308","Permanent Redirect");
+    statusMap.put("400","Bad Request");
+    statusMap.put("401","Unauthorized");
+    statusMap.put("402","Payment Required");
+    statusMap.put("403","Forbidden");
+    statusMap.put("404","Not Found");
+    statusMap.put("405","Method Not Allowed");
+    statusMap.put("406","Not Acceptable");
+    statusMap.put("407","Proxy Authentication Required");
+    statusMap.put("408","Request Timeout");
+    statusMap.put("409","Conflict");
+    statusMap.put("410","Gone");
+    statusMap.put("411","Length Required");
+    statusMap.put("412","Precondition Failed");
+    statusMap.put("413","Payload Too Large");
+    statusMap.put("414","URI Too Long");
+    statusMap.put("415","Unsupported Media Type");
+    statusMap.put("416","Requested Range Not Satisfiable");
+    statusMap.put("417","Expectation Failed");
+    statusMap.put("418","I'm a teapot");
+    statusMap.put("421","Misdirected Request");
+    statusMap.put("426","Upgrade Required");
+    statusMap.put("428","Precondition Required");
+    statusMap.put("429","Too Many Requests");
+    statusMap.put("431","Request Header Fields Too Large");
+    statusMap.put("500","Internal Server Error");
+    statusMap.put("501","Not Implemented");
+    statusMap.put("502","Bad Gateway");
+    statusMap.put("503","Service Unavailable");
+    statusMap.put("504","Gateway Timeout");
+    statusMap.put("505","HTTP Version Not Supported");
+    statusMap.put("506","Variant Also Negotiates");
+    statusMap.put("507","Variant Also Negotiates");
+    statusMap.put("511","Network Authentication Required");
+  }
+
+  public static String getStatusText(String code){
+    if(!statusMap.containsKey(code))
+      return UNKNOWN_STATUS;
+    return statusMap.get(code);
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/http/WXHttpUtil.java b/android/sdk/src/main/java/org/apache/weex/http/WXHttpUtil.java
new file mode 100644
index 0000000..d8f2577
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/http/WXHttpUtil.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.http;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import org.apache.weex.common.WXConfig;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.Map;
+
+/**
+ * Created by lixinke on 16/4/6.
+ */
+public class WXHttpUtil {
+
+  private static String sDefaultUA = null;
+
+  public static final String KEY_USER_AGENT = "user-agent";
+
+  public static String assembleUserAgent(Context ctx,Map<String, String> config) {
+    if (TextUtils.isEmpty(sDefaultUA)) {
+      StringBuilder builder = new StringBuilder();
+      builder.append(config.get(WXConfig.sysModel))
+          .append("(Android/")
+          .append(config.get(WXConfig.sysVersion))
+          .append(")")
+          .append(" ")
+
+          .append(TextUtils.isEmpty(config.get(WXConfig.appGroup)) ? "" : config.get(WXConfig.appGroup))
+          .append("(")
+          .append(TextUtils.isEmpty(config.get(WXConfig.appName)) ? "" : config.get(WXConfig.appName))
+          .append("/")
+          .append(config.get(WXConfig.appVersion))
+          .append(")")
+          .append(" ")
+
+          .append("Weex/")
+          .append(config.get(WXConfig.weexVersion))
+          .append(" ")
+
+          .append(TextUtils.isEmpty(config.get(WXConfig.externalUserAgent)) ? "" : config.get(WXConfig.externalUserAgent))
+          .append(TextUtils.isEmpty(config.get(WXConfig.externalUserAgent)) ? "" : " ")
+
+          .append(WXViewUtils.getScreenWidth(ctx) + "x" + WXViewUtils.getScreenHeight(ctx));
+      sDefaultUA = builder.toString();
+    }
+    return sDefaultUA;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/http/WXStreamModule.java b/android/sdk/src/main/java/org/apache/weex/http/WXStreamModule.java
new file mode 100644
index 0000000..ba3844b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/http/WXStreamModule.java
@@ -0,0 +1,383 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.http;
+
+import static org.apache.weex.http.WXHttpUtil.KEY_USER_AGENT;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXHttpAdapter;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.common.WXRequest;
+import org.apache.weex.common.WXResponse;
+import org.apache.weex.performance.WXStateRecord;
+import org.apache.weex.utils.WXLogUtils;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class WXStreamModule extends WXModule {
+
+  public static final String STATUS_TEXT = "statusText";
+  public static final String STATUS = "status";
+  final IWXHttpAdapter mAdapter;
+  static final Pattern CHARSET_PATTERN = Pattern.compile("charset=([a-z0-9-]+)");
+
+  public WXStreamModule(){
+    this(null);
+  }
+  public WXStreamModule(IWXHttpAdapter adapter){
+    mAdapter = adapter;
+  }
+
+  /**
+   * send HTTP request
+   *
+   * @param params   {method:POST/GET/PUT/DELETE/HEAD/PATCH,url:http://xxx,header:{key:value},
+   *                 body:{key:value}}
+   * @param callback formate:handler(err, response)
+   */
+  @Deprecated
+  @JSMethod(uiThread = false)
+  public void sendHttp(JSONObject paramsObj, final String callback) {
+
+    String method = paramsObj.getString("method");
+    String url = paramsObj.getString("url");
+    JSONObject headers = paramsObj.getJSONObject("header");
+    String body = paramsObj.getString("body");
+    int timeout = paramsObj.getIntValue("timeout");
+
+    if (method != null) method = method.toUpperCase(Locale.ROOT);
+    Options.Builder builder = new Options.Builder()
+            .setMethod(!"GET".equals(method)
+                    &&!"POST".equals(method)
+                    &&!"PUT".equals(method)
+                    &&!"DELETE".equals(method)
+                    &&!"HEAD".equals(method)
+                    &&!"PATCH".equals(method)?"GET":method)
+            .setUrl(url)
+            .setBody(body)
+            .setTimeout(timeout);
+
+    extractHeaders(headers,builder);
+    sendRequest(builder.createOptions(), new ResponseCallback() {
+      @Override
+      public void onResponse(WXResponse response, Map<String, String> headers) {
+        if(callback != null && mWXSDKInstance != null)
+          WXBridgeManager.getInstance().callback(mWXSDKInstance.getInstanceId(), callback,
+                  (response == null || response.originalData == null) ? "{}" :
+                          readAsString(response.originalData,
+                                  headers!=null?getHeader(headers,"Content-Type"):""
+                          ));
+      }
+    }, null, mWXSDKInstance.getInstanceId(), mWXSDKInstance.getBundleUrl());
+  }
+
+  /**
+   *
+   * @param optionsStr request options include:
+   *  method: GET 、POST、PUT、DELETE、HEAD、PATCH
+   *  headers:object,request header
+   *  url:
+   *  body: "Any body that you want to add to your request"
+   *  type: json、text、jsonp(json)
+   * @param callback finished callback,response object:
+   *  status:status code
+   *  ok:boolean is success,http status200~299
+   *  statusText: statusText
+   *  data:  option type is json,data is object,not data is string
+   *  headers: headers
+   *
+   * @param progressCallback in progress callback,for download progress and request state,response object:
+   *  readyState: number connection status 1 OPENED 2 HEADERS_RECEIVED 3 LOADING
+   *  status:status code
+   *  length:headers Content-Length
+   *  statusText:statusText
+   *  headers: headers
+   */
+  @JSMethod(uiThread = false)
+  public void fetch(JSONObject optionsObj , final JSCallback callback, JSCallback progressCallback){
+    fetch(optionsObj, callback, progressCallback, mWXSDKInstance.getInstanceId(), mWXSDKInstance.getBundleUrl());
+  }
+
+  public void fetch(JSONObject optionsObj , final JSCallback callback, JSCallback progressCallback, final String instanceId, String bundleURL){
+    boolean invaildOption = optionsObj==null || optionsObj.getString("url")==null;
+    if(invaildOption){
+      if(callback != null) {
+        Map<String, Object> resp = new HashMap<>();
+        resp.put("ok", false);
+        resp.put(STATUS_TEXT, Status.ERR_INVALID_REQUEST);
+        callback.invoke(resp);
+      }
+      return;
+    }
+    String method = optionsObj.getString("method");
+    String url = optionsObj.getString("url");
+    JSONObject headers = optionsObj.getJSONObject("headers");
+    String body = optionsObj.getString("body");
+    String type = optionsObj.getString("type");
+    int timeout = optionsObj.getIntValue("timeout");
+
+    WXSDKInstance wxsdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (wxsdkInstance != null) {
+      if (wxsdkInstance.getStreamNetworkHandler() != null) {
+        String localUrl = wxsdkInstance.getStreamNetworkHandler().fetchLocal(url);
+        if (!TextUtils.isEmpty(localUrl)) {
+          url = localUrl;
+        }
+      }
+    }
+
+    if (method != null) method = method.toUpperCase(Locale.ROOT);
+    Options.Builder builder = new Options.Builder()
+        .setMethod(!"GET".equals(method)
+            &&!"POST".equals(method)
+            &&!"PUT".equals(method)
+            &&!"DELETE".equals(method)
+            &&!"HEAD".equals(method)
+            &&!"PATCH".equals(method)?"GET":method)
+        .setUrl(url)
+        .setBody(body)
+        .setType(type)
+        .setTimeout(timeout);
+
+    extractHeaders(headers,builder);
+    final Options options = builder.createOptions();
+    sendRequest(options, new ResponseCallback() {
+      @Override
+      public void onResponse(WXResponse response, Map<String, String> headers) {
+        if(callback != null) {
+          Map<String, Object> resp = new HashMap<>();
+          if(response == null|| "-1".equals(response.statusCode)){
+            resp.put(STATUS,-1);
+            resp.put(STATUS_TEXT,Status.ERR_CONNECT_FAILED);
+          }else {
+            int code = Integer.parseInt(response.statusCode);
+            resp.put(STATUS, code);
+            resp.put("ok", (code >= 200 && code <= 299));
+            if (response.originalData == null) {
+              resp.put("data", null);
+            } else {
+              String respData = readAsString(response.originalData,
+                  headers != null ? getHeader(headers, "Content-Type") : ""
+              );
+              try {
+                resp.put("data", parseData(respData, options.getType()));
+              } catch (JSONException exception) {
+                WXLogUtils.e("", exception);
+                resp.put("ok", false);
+                resp.put("data","{'err':'Data parse failed!'}");
+              }
+            }
+            resp.put(STATUS_TEXT, Status.getStatusText(response.statusCode));
+          }
+          resp.put("headers", headers);
+          WXStateRecord
+              .getInstance().recordAction(instanceId,"stream response code:"+(null!= response?response.statusCode:"null"));
+          callback.invoke(resp);
+        }
+      }
+    }, progressCallback, instanceId, bundleURL);
+  }
+
+  Object parseData(String data, Options.Type type) throws JSONException{
+    if( type == Options.Type.json){
+      return JSONObject.parse(data);
+    }else if( type == Options.Type.jsonp){
+      if(data == null || data.isEmpty()) {
+        return new JSONObject();
+      }
+      int b = data.indexOf("(")+1;
+      int e = data.lastIndexOf(")");
+      if(b ==0 || b >= e || e <= 0){
+        return new JSONObject();
+      }
+
+      data = data.substring(b,e);
+      return JSONObject.parse(data);
+    }else {
+      return data;
+    }
+  }
+
+  static String getHeader(Map<String,String> headers,String key){
+    if(headers == null||key == null){
+      return null;
+    }
+    if(headers.containsKey(key)){
+      return headers.get(key);
+    }else{
+      return headers.get(key.toLowerCase(Locale.ROOT));
+    }
+  }
+
+
+
+  static String readAsString(byte[] data,String cType){
+    String charset = "utf-8";
+    if(cType != null){
+      Matcher matcher = CHARSET_PATTERN.matcher(cType.toLowerCase(Locale.ROOT));
+      if(matcher.find()){
+        charset = matcher.group(1);
+      }
+    }
+    try {
+      return new String(data,charset);
+    } catch (UnsupportedEncodingException e) {
+      WXLogUtils.e("", e);
+      return new String(data);
+    }
+  }
+
+
+  private void extractHeaders(JSONObject headers, Options.Builder builder){
+    //set user-agent
+    String UA = WXHttpUtil.assembleUserAgent(WXEnvironment.getApplication(),WXEnvironment.getConfig());
+    if(headers != null){
+      for (String key : headers.keySet()) {
+        if (key.equals(KEY_USER_AGENT)) {
+          UA = headers.getString(key);
+          continue;
+        }
+        builder.putHeader(key, headers.getString(key));
+      }
+    }
+    builder.putHeader(KEY_USER_AGENT,UA);
+  }
+
+
+  private void sendRequest(Options options,ResponseCallback callback,JSCallback progressCallback,String instanceId, String bundleURL){
+    WXRequest wxRequest = new WXRequest();
+    wxRequest.method = options.getMethod();
+    wxRequest.url = WXSDKManager.getInstance().getURIAdapter().rewrite(bundleURL, URIAdapter.REQUEST,Uri.parse(options.getUrl())).toString();
+    wxRequest.body = options.getBody();
+    wxRequest.timeoutMs = options.getTimeout();
+    wxRequest.instanceId = instanceId;
+
+    if(options.getHeaders()!=null) {
+      if (wxRequest.paramMap == null) {
+        wxRequest.paramMap = options.getHeaders();
+      } else {
+        wxRequest.paramMap.putAll(options.getHeaders());
+      }
+    }
+
+    IWXHttpAdapter adapter = ( mAdapter==null) ? WXSDKManager.getInstance().getIWXHttpAdapter() : mAdapter;
+    if (adapter != null) {
+      adapter.sendRequest(wxRequest, new StreamHttpListener(callback,progressCallback));
+    }else{
+      WXLogUtils.e("WXStreamModule","No HttpAdapter found,request failed.");
+    }
+  }
+
+  private interface ResponseCallback{
+    void onResponse(WXResponse response, Map<String, String> headers);
+  }
+
+  private static class StreamHttpListener implements IWXHttpAdapter.OnHttpListener {
+    private ResponseCallback mCallback;
+    private JSCallback mProgressCallback;
+    private Map<String,Object> mResponse = new HashMap<>();
+    private Map<String,String> mRespHeaders;
+
+    private StreamHttpListener(ResponseCallback callback,JSCallback progressCallback) {
+      mCallback = callback;
+      mProgressCallback = progressCallback;
+    }
+
+
+    @Override
+    public void onHttpStart() {
+      if(mProgressCallback !=null) {
+        mResponse.put("readyState",1);//readyState: number 1 OPENED 2 HEADERS_RECEIVED 3 LOADING
+        mResponse.put("length",0);
+        mProgressCallback.invokeAndKeepAlive(new HashMap<>(mResponse));
+      }
+    }
+
+    @Override
+    public void onHttpUploadProgress(int uploadProgress) {
+
+    }
+
+    @Override
+    public void onHeadersReceived(int statusCode,Map<String,List<String>> headers) {
+      mResponse.put("readyState", 2);
+      mResponse.put("status", statusCode);
+
+      Map<String, String> simpleHeaders = new HashMap<>();
+      if (headers != null) {
+        Iterator<Map.Entry<String, List<String>>> it = headers.entrySet().iterator();
+        while (it.hasNext()) {
+          Map.Entry<String, List<String>> entry = it.next();
+          if (entry.getValue().size() == 0) {
+            continue;
+          } else if (entry.getValue().size() == 1)
+            simpleHeaders.put(entry.getKey() == null ? "_" : entry.getKey(), entry.getValue().get(0));
+          else {
+            simpleHeaders.put(entry.getKey() == null ? "_" : entry.getKey(), entry.getValue().toString());
+          }
+        }
+      }
+
+      mResponse.put("headers", simpleHeaders);
+      mRespHeaders = simpleHeaders;
+      if (mProgressCallback != null) {
+        mProgressCallback.invokeAndKeepAlive(new HashMap<>(mResponse));
+      }
+    }
+
+    @Override
+    public void onHttpResponseProgress(int loadedLength) {
+      mResponse.put("length",loadedLength);
+      if(mProgressCallback!=null){
+        mProgressCallback.invokeAndKeepAlive(new HashMap<>(mResponse));
+      }
+
+    }
+
+    @Override
+    public void onHttpFinish(final WXResponse response) {
+      //compatible with old sendhttp
+      if(mCallback!=null){
+        mCallback.onResponse(response, mRespHeaders);
+      }
+
+      if(WXEnvironment.isApkDebugable()){
+        WXLogUtils.d("WXStreamModule",response!=null && response.originalData!=null?new String(response.originalData):"response data is NUll!");
+      }
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/instance/InstanceOnFireEventInterceptor.java b/android/sdk/src/main/java/org/apache/weex/instance/InstanceOnFireEventInterceptor.java
new file mode 100644
index 0000000..dd5915d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/instance/InstanceOnFireEventInterceptor.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.instance;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by furture on 2018/8/23.
+ */
+
+public abstract  class InstanceOnFireEventInterceptor {
+
+    private List<String> listenEvents;
+
+    public InstanceOnFireEventInterceptor() {
+        this.listenEvents = new ArrayList<>();
+    }
+
+    public void addInterceptEvent(String event){
+        if(!listenEvents.contains(event)){
+            this.listenEvents.add(event);
+        }
+    }
+
+    public List<String> getListenEvents() {
+        return listenEvents;
+    }
+
+    public void onInterceptFireEvent(String instanceId, String elementRef, String type, Map<String, Object> params, Map<String, Object> domChanges){
+        if(params == null){
+            return;
+        }
+        if(this.listenEvents.contains(type)){
+            onFireEvent(instanceId, elementRef, type, params, domChanges);
+        }
+    }
+
+    public  abstract void onFireEvent(String instanceId, String elementRef,String type, Map<String, Object> params, Map<String, Object> domChanges);
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/layout/ContentBoxMeasurement.java b/android/sdk/src/main/java/org/apache/weex/layout/ContentBoxMeasurement.java
new file mode 100644
index 0000000..309c2bf
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/layout/ContentBoxMeasurement.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.layout;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import org.apache.weex.base.CalledByNative;
+import org.apache.weex.common.Destroyable;
+import org.apache.weex.ui.component.WXComponent;
+
+import java.io.Serializable;
+
+public abstract class ContentBoxMeasurement implements Serializable, Destroyable {
+
+  @Nullable
+  protected WXComponent mComponent;
+
+  protected float mMeasureWidth;
+
+  protected float mMeasureHeight;
+
+  public ContentBoxMeasurement() {
+    mComponent = null;
+  }
+
+  public ContentBoxMeasurement(@NonNull WXComponent component) {
+    this.mComponent = component;
+  }
+
+  /** uiThread = false **/
+  @CalledByNative
+  public final void measure(float width, float height, int widthMeasureMode, int heightMeasureMode) {
+    measureInternal(width, height, widthMeasureMode, heightMeasureMode);
+  }
+
+  /** uiThread = false **/
+  public abstract void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode);
+
+  /** uiThread = false **/
+  @CalledByNative
+  public abstract void layoutBefore();
+
+  /** uiThread = false **/
+  @CalledByNative
+  public abstract void layoutAfter(float computedWidth, float computedHeight);
+
+  @CalledByNative
+  public float getWidth() {
+    return mMeasureWidth;
+  }
+
+  @CalledByNative
+  public float getHeight() {
+    return mMeasureHeight;
+  }
+
+  @Override
+  public void destroy() {
+    mComponent = null;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/layout/MeasureMode.java b/android/sdk/src/main/java/org/apache/weex/layout/MeasureMode.java
new file mode 100644
index 0000000..c44b49b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/layout/MeasureMode.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.layout;
+
+import java.io.Serializable;
+
+public class MeasureMode implements Serializable {
+
+  public static int EXACTLY = 1;
+
+  public static int UNSPECIFIED = 0;
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/layout/MeasureSize.java b/android/sdk/src/main/java/org/apache/weex/layout/MeasureSize.java
new file mode 100644
index 0000000..476027e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/layout/MeasureSize.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.layout;
+
+import java.io.Serializable;
+
+public class MeasureSize implements Serializable{
+  private float width;
+  private float height;
+
+  public float getWidth() {
+    return width;
+  }
+
+  public void setWidth(float width) {
+    this.width = width;
+  }
+
+  public float getHeight() {
+    return height;
+  }
+
+  public void setHeight(float height) {
+    this.height = height;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/layout/measurefunc/TextContentBoxMeasurement.java b/android/sdk/src/main/java/org/apache/weex/layout/measurefunc/TextContentBoxMeasurement.java
new file mode 100755
index 0000000..dca61a0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/layout/measurefunc/TextContentBoxMeasurement.java
@@ -0,0 +1,493 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.layout.measurefunc;
+
+import android.graphics.Canvas;
+import android.os.Build;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.Editable;
+import android.text.Layout;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.style.AlignmentSpan;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.annotation.WorkerThread;
+
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.TextDecorationSpan;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.dom.WXCustomStyleSpan;
+import org.apache.weex.dom.WXLineHeightSpan;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import org.apache.weex.layout.MeasureMode;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXText;
+import org.apache.weex.ui.component.WXTextDecoration;
+import org.apache.weex.utils.WXDomUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXResourceUtils;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.apache.weex.dom.WXStyle.UNSET;
+import static org.apache.weex.utils.WXUtils.isUndefined;
+
+/**
+ * Created by miomin on 2018/3/9.
+ */
+
+public class TextContentBoxMeasurement extends ContentBoxMeasurement {
+
+  private static final Canvas DUMMY_CANVAS = new Canvas();
+
+  public TextContentBoxMeasurement(WXComponent component) {
+    super(component);
+  }
+
+  class SetSpanOperation {
+
+    protected final int start, end, flag;
+    protected final Object what;
+
+    SetSpanOperation(int start, int end, Object what) {
+      this(start, end, what, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+    }
+
+    SetSpanOperation(int start, int end, Object what, int flag) {
+      this.start = start;
+      this.end = end;
+      this.what = what;
+      this.flag = flag;
+    }
+
+    public void execute(Spannable sb) {
+      sb.setSpan(what, start, end, flag);
+    }
+  }
+
+  private static final String ELLIPSIS = "\u2026";
+  private boolean mIsColorSet = false;
+  private boolean hasBeenMeasured = false;
+  private int mColor;
+  private int mFontStyle = UNSET;
+  private int mFontWeight = UNSET;
+  private int mNumberOfLines = UNSET;
+  private int mFontSize = UNSET;
+  private int mLineHeight = UNSET;
+  private float previousWidth = Float.NaN;
+  private String mFontFamily = null;
+  private String mText = null;
+  private TextUtils.TruncateAt textOverflow;
+  private Layout.Alignment mAlignment;
+  private WXTextDecoration mTextDecoration = WXTextDecoration.NONE;
+  private TextPaint mTextPaint;
+  private @Nullable
+  Spanned spanned;
+  private @Nullable
+  Layout layout;
+  private AtomicReference<Layout> atomicReference = new AtomicReference<>();
+
+  /**
+   * uiThread = false
+   **/
+  @Override
+  public void layoutBefore() {
+    mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
+    hasBeenMeasured = false;
+    updateStyleAndText();
+    spanned = createSpanned(mText);
+  }
+
+  /**
+   * uiThread = false
+   **/
+  @Override
+  public void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode) {
+    float measureWidth = width, measureHeight = height;
+    hasBeenMeasured = true;
+    float textWidth = getTextWidth(mTextPaint, width, widthMeasureMode == MeasureMode.EXACTLY);
+
+    if (textWidth > 0 && spanned != null) {
+      layout = createLayout(textWidth,null);
+      previousWidth = layout.getWidth();
+      if (Float.isNaN(width)) {
+        measureWidth = layout.getWidth();
+      } else {
+        measureWidth = Math.min(layout.getWidth(), measureWidth);
+      }
+
+      if (Float.isNaN(height)) {
+        measureHeight = layout.getHeight();
+      }
+    } else {
+      if (widthMeasureMode == MeasureMode.UNSPECIFIED) {
+        measureWidth = 0;
+      }
+      if (heightMeasureMode == MeasureMode.UNSPECIFIED) {
+        measureHeight = 0;
+      }
+    }
+    mMeasureWidth = measureWidth;
+    mMeasureHeight = measureHeight;
+  }
+
+  /**
+   * uiThread = false
+   **/
+  @Override
+  public void layoutAfter(float computedWidth, float computedHeight) {
+    if(mComponent!=null) {
+      if (hasBeenMeasured) {
+        if (layout != null &&
+            WXDomUtils
+                .getContentWidth(mComponent.getPadding(), mComponent.getBorder(), computedWidth)
+                != previousWidth) {
+          recalculateLayout(computedWidth);
+        }
+      } else {
+        updateStyleAndText();
+        recalculateLayout(computedWidth);
+      }
+      hasBeenMeasured = false;
+      if (layout != null && !layout.equals(atomicReference.get()) &&
+          Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+        if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
+          warmUpTextLayoutCache(layout);
+        }
+      }
+      swap();
+      WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
+        @Override
+        public void run() {
+          if(mComponent!=null) {
+            mComponent.updateExtra(atomicReference.get());
+          }
+        }
+      }, mComponent.getInstanceId());
+    }
+  }
+
+  private void updateStyleAndText() {
+    updateStyleImp(mComponent.getStyles());
+    mText = WXAttr.getValue(mComponent.getAttrs());
+  }
+
+  /**
+   * Force relayout the text, the text must layout before invoke this method.
+   *
+   * Internal method, do not invoke unless you what what you are doing
+   * @param isRTL
+   */
+  @RestrictTo(Scope.LIBRARY)
+  @WorkerThread
+  public void forceRelayout(){
+    //Generate Spans
+    layoutBefore();
+
+    //Measure
+    measure(previousWidth, Float.NaN, MeasureMode.EXACTLY, MeasureMode.UNSPECIFIED);
+
+    //Swap text layout to UI Thread
+    layoutAfter(previousWidth, Float.NaN);
+  }
+
+  /**
+   * Record the property according to the given style
+   *
+   * @param style the give style.
+   */
+  private void updateStyleImp(Map<String, Object> style) {
+    if (style != null) {
+      if (style.containsKey(Constants.Name.LINES)) {
+        int lines = WXStyle.getLines(style);
+        mNumberOfLines = lines > 0 ? lines : UNSET;
+      }
+      if (style.containsKey(Constants.Name.FONT_SIZE)) {
+        mFontSize = WXStyle.getFontSize(style, mComponent.getViewPortWidth());
+      }
+      if (style.containsKey(Constants.Name.FONT_WEIGHT)) {
+        mFontWeight = WXStyle.getFontWeight(style);
+      }
+      if (style.containsKey(Constants.Name.FONT_STYLE)) {
+        mFontStyle = WXStyle.getFontStyle(style);
+      }
+      if (style.containsKey(Constants.Name.COLOR)) {
+        mColor = WXResourceUtils.getColor(WXStyle.getTextColor(style));
+        mIsColorSet = mColor != Integer.MIN_VALUE;
+      }
+      if (style.containsKey(Constants.Name.TEXT_DECORATION)) {
+        mTextDecoration = WXStyle.getTextDecoration(style);
+      }
+      if (style.containsKey(Constants.Name.FONT_FAMILY)) {
+        mFontFamily = WXStyle.getFontFamily(style);
+      }
+      mAlignment = WXStyle.getTextAlignment(style, mComponent.isLayoutRTL());
+      textOverflow = WXStyle.getTextOverflow(style);
+      int lineHeight = WXStyle.getLineHeight(style, mComponent.getViewPortWidth());
+      if (lineHeight != UNSET) {
+        mLineHeight = lineHeight;
+      }
+    }
+  }
+
+  /**
+   * Update {@link #spanned} according to the give charSequence and styles
+   *
+   * @param text the give raw text.
+   * @return an Spanned contains text and spans
+   */
+  protected
+  @NonNull
+  Spanned createSpanned(String text) {
+    if (!TextUtils.isEmpty(text)) {
+      SpannableString spannable = new SpannableString(text);
+      updateSpannable(spannable, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+      return spannable;
+    }
+    return new SpannableString("");
+  }
+
+  protected void updateSpannable(Spannable spannable, int spanFlag) {
+    int end = spannable.length();
+    if (mFontSize == UNSET) {
+      mTextPaint.setTextSize(WXText.sDEFAULT_SIZE);
+    }
+    else{
+      mTextPaint.setTextSize(mFontSize);
+    }
+
+    if (mLineHeight != UNSET) {
+      setSpan(spannable, new WXLineHeightSpan(mLineHeight), 0, end, spanFlag);
+    }
+
+    setSpan(spannable, new AlignmentSpan.Standard(mAlignment), 0, end, spanFlag);
+
+    if (mFontStyle != UNSET || mFontWeight != UNSET || mFontFamily != null) {
+      setSpan(spannable, new WXCustomStyleSpan(mFontStyle, mFontWeight, mFontFamily), 0, end, spanFlag);
+    }
+
+    if (mIsColorSet) {
+      mTextPaint.setColor(mColor);
+    }
+
+    if (mTextDecoration == WXTextDecoration.UNDERLINE || mTextDecoration == WXTextDecoration.LINETHROUGH) {
+      setSpan(spannable, new TextDecorationSpan(mTextDecoration), 0, end, spanFlag);
+    }
+  }
+
+  private void setSpan(Spannable spannable, Object what, int start, int end, int spanFlag){
+    spannable.setSpan(what, start, end, spanFlag);
+  }
+
+  /**
+   * Get text width according to constrain of outerWidth with and forceToDesired
+   *
+   * @param textPaint      paint used to measure text
+   * @param outerWidth     the width that css-layout desired.
+   * @param forceToDesired if set true, the return value will be outerWidth, no matter what the width
+   *                       of text is.
+   * @return if forceToDesired is false, it will be the minimum value of the width of text and
+   * outerWidth in case of outerWidth is defined, in other case, it will be outer width.
+   */
+  private float getTextWidth(TextPaint textPaint, float outerWidth, boolean forceToDesired) {
+    if (mText == null) {
+      if (forceToDesired) {
+        return outerWidth;
+      }
+      return 0;
+    }
+    else {
+      float textWidth;
+      if (forceToDesired) {
+        textWidth = outerWidth;
+      } else {
+        float desiredWidth = Layout.getDesiredWidth(spanned, textPaint);
+        if (isUndefined(outerWidth) || desiredWidth < outerWidth) {
+          textWidth = desiredWidth;
+        } else {
+          textWidth = outerWidth;
+        }
+      }
+      return textWidth;
+    }
+  }
+
+  /**
+   * Update layout according to {@link #mText} and span
+   *
+   * @param width          the specified width.
+   * @param forceWidth     If true, force the text width to the specified width, otherwise, text width
+   *                       may equals to or be smaller than the specified width.
+   * @param previousLayout the result of previous layout, could be null.
+   */
+  private
+  @NonNull
+  Layout createLayout(final float textWidth, @Nullable Layout previousLayout) {
+    Layout layout;
+    if (previousWidth != textWidth || previousLayout == null) {
+      layout = new StaticLayout(spanned, mTextPaint, (int) Math.ceil(textWidth),
+              Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
+    } else {
+      layout = previousLayout;
+    }
+    if (mNumberOfLines != UNSET && mNumberOfLines > 0 && mNumberOfLines < layout.getLineCount()) {
+      int lastLineStart, lastLineEnd;
+      lastLineStart = layout.getLineStart(mNumberOfLines - 1);
+      lastLineEnd = layout.getLineEnd(mNumberOfLines - 1);
+      if (lastLineStart < lastLineEnd) {
+        SpannableStringBuilder builder = null;
+        if (lastLineStart > 0) {
+          builder = new SpannableStringBuilder(spanned.subSequence(0, lastLineStart));
+        } else {
+          builder = new SpannableStringBuilder();
+        }
+        Editable lastLine = new SpannableStringBuilder(spanned.subSequence(lastLineStart, lastLineEnd));
+        builder.append(truncate(lastLine, mTextPaint, (int) Math.ceil(textWidth), textOverflow));
+        adjustSpansRange(spanned, builder);
+        spanned = builder;
+        return new StaticLayout(spanned, mTextPaint, (int) Math.ceil(textWidth),
+                Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
+      }
+    }
+    return layout;
+  }
+
+  /**
+   * Truncate the source span to the specified lines.
+   * Caller of this method must ensure that the lines of text is <strong>greater than desired lines and need truncate</strong>.
+   * Otherwise, unexpected behavior may happen.
+   *
+   * @param source     The source span.
+   * @param paint      the textPaint
+   * @param desired    specified lines.
+   * @param truncateAt truncate method, null value means clipping overflow text directly, non-null value means using ellipsis strategy to clip
+   * @return The spans after clipped.
+   */
+  private
+  @NonNull
+  Spanned truncate(@Nullable Editable source, @NonNull TextPaint paint,
+                   int desired, @Nullable TextUtils.TruncateAt truncateAt) {
+    Spanned ret = new SpannedString("");
+    if (!TextUtils.isEmpty(source) && source.length() > 0) {
+      if (truncateAt != null) {
+        source.append(ELLIPSIS);
+        Object[] spans = source.getSpans(0, source.length(), Object.class);
+        for (Object span : spans) {
+          int start = source.getSpanStart(span);
+          int end = source.getSpanEnd(span);
+          if (start == 0 && end == source.length() - 1) {
+            source.removeSpan(span);
+            source.setSpan(span, 0, source.length(), source.getSpanFlags(span));
+          }
+        }
+      }
+
+      StaticLayout layout;
+      int startOffset;
+
+      while (source.length() > 1) {
+        startOffset = source.length() - 1;
+        if (truncateAt != null) {
+          startOffset -= 1;
+        }
+        source.delete(startOffset, startOffset + 1);
+        layout = new StaticLayout(source, paint, desired, Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
+        if (layout.getLineCount() <= 1) {
+          ret = source;
+          break;
+        }
+      }
+    }
+    return ret;
+  }
+
+  /**
+   * Adjust span range after truncate due to the wrong span range during span copy and slicing.
+   *
+   * @param beforeTruncate The span before truncate
+   * @param afterTruncate  The span after truncate
+   */
+  private void adjustSpansRange(@NonNull Spanned beforeTruncate, @NonNull Spannable afterTruncate) {
+    Object[] spans = beforeTruncate.getSpans(0, beforeTruncate.length(), Object.class);
+    for (Object span : spans) {
+      int start = beforeTruncate.getSpanStart(span);
+      int end = beforeTruncate.getSpanEnd(span);
+      if (start == 0 && end == beforeTruncate.length()) {
+        afterTruncate.removeSpan(span);
+        afterTruncate.setSpan(span, 0, afterTruncate.length(), beforeTruncate.getSpanFlags(span));
+      }
+    }
+  }
+
+  private void recalculateLayout(float computedWidth) {
+    float contentWidth = WXDomUtils.getContentWidth(mComponent.getPadding(), mComponent.getBorder(), computedWidth);
+    if (contentWidth > 0) {
+      spanned = createSpanned(mText);
+      if (spanned != null) {
+        layout = createLayout(contentWidth, layout);
+        previousWidth = layout.getWidth();
+      } else {
+        previousWidth = 0;
+      }
+    }
+  }
+
+  /**
+   * As warming up TextLayoutCache done in the DOM thread may manipulate UI operation,
+   * there may be some exception, in which case the exception is ignored. After all,
+   * this is just a warm up operation.
+   *
+   * @return false for warm up failure, otherwise returns true.
+   */
+  private boolean warmUpTextLayoutCache(Layout layout) {
+    boolean result;
+    try {
+      layout.draw(DUMMY_CANVAS);
+      result = true;
+    } catch (Exception e) {
+      WXLogUtils.eTag("TextWarmUp", e);
+      result = false;
+    }
+    return result;
+  }
+
+  /**
+   * Move the reference of current layout to the {@link AtomicReference} for further use,
+   * then clear current layout.
+   */
+  private void swap() {
+    if (layout != null) {
+      atomicReference.set(layout);
+      layout = null;
+    }
+    hasBeenMeasured = false;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/performance/IApmGenerator.java b/android/sdk/src/main/java/org/apache/weex/performance/IApmGenerator.java
new file mode 100644
index 0000000..45fb7bd
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/performance/IApmGenerator.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.performance;
+
+public interface IApmGenerator {
+    /**
+     * @param type apm type
+     * @return impl
+     */
+    IWXApmMonitorAdapter generateApmInstance(String type);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/performance/IWXAnalyzer.java b/android/sdk/src/main/java/org/apache/weex/performance/IWXAnalyzer.java
new file mode 100644
index 0000000..5015f01
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/performance/IWXAnalyzer.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.performance;
+
+
+/**
+ * @author zhongcang
+ * @date 2018/2/28
+ */
+
+public interface IWXAnalyzer {
+
+  /**
+   *
+   * @param group   dataGroup
+   * @param module  dataModule in group
+   * @param type    dataType
+   * @param data   data (json)
+   */
+  void transfer(String group, String module, String type, String data);
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/performance/IWXApmMonitorAdapter.java b/android/sdk/src/main/java/org/apache/weex/performance/IWXApmMonitorAdapter.java
new file mode 100644
index 0000000..de1c56f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/performance/IWXApmMonitorAdapter.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.performance;
+
+public interface IWXApmMonitorAdapter {
+
+    /**
+     * start record
+     *
+     * @param instanceId instanceId
+     */
+    void onStart(String instanceId);
+
+    /**
+     * end record
+     */
+    void onEnd();
+
+    /**
+     * record event
+     */
+    void onEvent(String name, Object value);
+
+    /**
+     * record stage
+     */
+    void onStage(String name, long timestamp);
+
+    /**
+     * record property
+     */
+    void addProperty(String key, Object value);
+
+    /**
+     * record statistic
+     */
+    void addStats(String key, double value);
+
+    /**
+     * record subProcedure stage
+     */
+
+    void onSubProcedureStage(String procedureName, String stageName);
+
+    /**
+     * record SubProcedure event
+     */
+
+    void onSubProcedureEvent(String procedureName, String eventName);
+
+    /**
+     * record subProcedure stats
+     */
+    void setSubProcedureStats(String procedureName, String name, double value);
+
+    /**
+     * record subProcedure properties
+     */
+    void setSubProcedureProperties(String procedureName, String name, Object value);
+
+    void onAppear();
+
+    void onDisappear();
+
+    String parseReportUrl(String originUrl);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/performance/WXAnalyzerDataTransfer.java b/android/sdk/src/main/java/org/apache/weex/performance/WXAnalyzerDataTransfer.java
new file mode 100644
index 0000000..17e069c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/performance/WXAnalyzerDataTransfer.java
@@ -0,0 +1,167 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.performance;
+
+import java.util.Iterator;
+import java.util.List;
+
+import android.util.Log;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXJSExceptionInfo;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXUtils;
+import org.json.JSONObject;
+
+/**
+ * @author zhongcang
+ * @date 2018/2/28
+ */
+
+public class WXAnalyzerDataTransfer {
+
+  private static final String GROUP = "WXAnalyzer";
+  private static final String MODULE_ERROR = "WXError";
+  private static final String MODULE_WX_APM = "wxapm";
+  public static boolean isOpenPerformance = false;
+  public static final String INTERACTION_TAG = "wxInteractionAnalyzer";
+  private static boolean sOpenInteractionLog;
+
+
+  public static void transferPerformance(String instanceId,String type,String key,Object value)
+  {
+      if (!isOpenPerformance){
+          return;
+      }
+      if (sOpenInteractionLog && "stage".equals(type)){
+          Log.d(INTERACTION_TAG, "[client][stage]"+instanceId+","+key+","+value);
+      }
+      List<IWXAnalyzer> transferList = WXSDKManager.getInstance().getWXAnalyzerList();
+      if (null == transferList || transferList.size() == 0) {
+          return;
+      }
+
+      WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+      if (null == instance){
+          return;
+      }
+
+      String data;
+      try {
+        data = new JSONObject().put(key,value).toString();
+      }catch (Exception e){
+        e.printStackTrace();
+        return;
+      }
+
+      Iterator<IWXAnalyzer> itr = transferList.iterator();
+      while (itr.hasNext()){
+          IWXAnalyzer item = itr.next();
+          item.transfer(MODULE_WX_APM, instance.getInstanceId(), type, data);
+      }
+  }
+
+  public static void transferInteractionInfo(WXComponent targetComponent){
+    if (!isOpenPerformance){
+      return;
+    }
+
+    List<IWXAnalyzer> transferList = WXSDKManager.getInstance().getWXAnalyzerList();
+    if (null == transferList || transferList.size() == 0) {
+      return;
+    }
+    long renderOriginDiffTime = WXUtils.getFixUnixTime() - targetComponent.getInstance().getWXPerformance().renderUnixTimeOrigin;
+    String data;
+    try{
+      data = new JSONObject()
+          .put("renderOriginDiffTime",renderOriginDiffTime)
+          .put("type",targetComponent.getComponentType())
+          .put("ref",targetComponent.getRef())
+          .put("style",targetComponent.getStyles())
+          .put("attrs",targetComponent.getAttrs())
+          .toString();
+    }catch (Exception e){
+      e.printStackTrace();
+      return;
+    }
+    for (IWXAnalyzer transfer : transferList) {
+      transfer.transfer(MODULE_WX_APM, targetComponent.getInstanceId(), "wxinteraction", data);
+    }
+  }
+
+
+  public static void transferError(WXJSExceptionInfo exceptionInfo, String instanceId) {
+    if (!WXEnvironment.isApkDebugable()) {
+      return;
+    }
+    List<IWXAnalyzer> transferList = WXSDKManager.getInstance().getWXAnalyzerList();
+    if (null == transferList || transferList.size() == 0) {
+      return;
+    }
+
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (null == instance) {
+      return;
+    }
+    WXErrorCode errorCode = exceptionInfo.getErrCode();
+    String data = "";
+    try {
+      data = new JSONObject()
+              .put("instanceId", instanceId)
+              .put("url", instance.getBundleUrl())
+              .put("errorCode", errorCode.getErrorCode())
+              .put("errorMsg", errorCode.getErrorMsg())
+              .put("errorGroup", errorCode.getErrorGroup())
+              .toString();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    for (IWXAnalyzer transfer : transferList) {
+      transfer.transfer(GROUP, MODULE_ERROR, errorCode.getErrorType().toString(), data);
+    }
+  }
+
+  public static void switchInteractionLog(final boolean isOpen){
+      if ( sOpenInteractionLog == isOpen || !WXEnvironment.JsFrameworkInit){
+          return;
+      }
+      sOpenInteractionLog = isOpen;
+      //for jsfm && jsengin
+      //TODO wait for JSFramework
+//      WXBridgeManager.getInstance().post(new Runnable() {
+//          @Override
+//          public void run() {
+//              WXJSObject[] args = {new WXJSObject(isOpen?1:0)};
+//              WXBridgeManager.getInstance().invokeExecJS(
+//                  "",
+//                  null,
+//                  "switchInteractionLog",
+//                  args,
+//                  false);
+//          }
+//      });
+      //for weex_core
+      WXBridgeManager.getInstance().registerCoreEnv("switchInteractionLog",String.valueOf(isOpen));
+  }
+
+  public static boolean isInteractionLogOpen(){
+     return sOpenInteractionLog;
+  }
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/performance/WXInstanceApm.java b/android/sdk/src/main/java/org/apache/weex/performance/WXInstanceApm.java
new file mode 100644
index 0000000..39d9019
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/performance/WXInstanceApm.java
@@ -0,0 +1,683 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.performance;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.util.Log;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXPerformance;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+public class WXInstanceApm {
+
+    public static final String WEEX_PAGE_TOPIC = "weex_page";
+
+    /************** properties *****************/
+    public static final String KEY_PROPERTIES_ERROR_CODE = "wxErrorCode";
+    //public static final String KEY_PAGE_PROPERTIES_LAUNCH_ID = "wxLaunchId";
+    public static final String KEY_PAGE_PROPERTIES_BIZ_ID = "wxBizID";
+    public static final String KEY_PAGE_PROPERTIES_BUBDLE_URL = "wxBundleUrl";
+    public static final String KEY_PAGE_PROPERTIES_JSLIB_VERSION = "wxJSLibVersion";
+    public static final String KEY_PAGE_PROPERTIES_WEEX_VERSION = "wxSDKVersion";
+    public static final String KEY_PAGE_PROPERTIES_REQUEST_TYPE = "wxRequestType";
+    public static final String KEY_PAGE_PROPERTIES_CACHE_TYPE = "wxCacheType";
+    public static final String KEY_PAGE_PROPERTIES_CACHE_INFO = "wxZCacheInfo";
+    public static final String KEY_PAGE_PROPERTIES_JS_FM_INI = "wxJsFrameworkInit";
+    public static final String KEY_PAGE_PROPERTIES_CONTAINER_NAME = "wxContainerName";
+    public static final String KEY_PAGE_PROPERTIES_INSTANCE_TYPE = "wxInstanceType";
+    public static final String KEY_PAGE_PROPERTIES_PARENT_PAGE = "wxParentPage";
+    public static final String KEY_PAGE_PROPERTIES_BUNDLE_TYPE = "wxBundleType";
+    public static final String KEY_PAGE_PROPERTIES_RENDER_TYPE = "wxRenderType";
+    public static final String KEY_PAGE_PROPERTIES_UIKIT_TYPE = "wxUIKitType";
+
+    /************** stages *****************/
+    public static final String KEY_PAGE_STAGES_CONTAINER_READY = "wxContainerReady";
+    public static final String KEY_PAGE_STAGES_DOWN_BUNDLE_START = "wxStartDownLoadBundle";
+    public static final String KEY_PAGE_STAGES_DOWN_BUNDLE_END = "wxEndDownLoadBundle";
+    public static final String KEY_PAGE_STAGES_RENDER_ORGIGIN = "wxRenderTimeOrigin";
+    public static final String KEY_PAGE_STAGES_LOAD_BUNDLE_START = "wxStartLoadBundle";
+    public static final String KEY_PAGE_STAGES_LOAD_BUNDLE_END = "wxEndLoadBundle";
+    public static final String KEY_PAGE_STAGES_FIRST_INTERACTION_VIEW = "wxFirstInteractionView";
+    public static final String KEY_PAGE_STAGES_CREATE_FINISH= "wxJSBundleCreateFinish";
+    public static final String KEY_PAGE_STAGES_FSRENDER = "wxFsRender";
+    public static final String KEY_PAGE_STAGES_NEW_FSRENDER = "wxNewFsRender";
+    public static final String KEY_PAGE_STAGES_END_EXCUTE_BUNDLE = "wxEndExecuteBundle";
+    public static final String KEY_PAGE_STAGES_INTERACTION = "wxInteraction";
+    public static final String KEY_PAGE_STAGES_DESTROY = "wxDestroy";
+
+    //Custom preprocessing start, called when activity created or other time. Called by other activity
+    public static final String KEY_PAGE_STAGES_CUSTOM_PREPROCESS_START = "wxCustomPreprocessStart";
+    //Custom preprocessing end, called when you'are able to start weex render. Called by other activity
+    public static final String KEY_PAGE_STAGES_CUSTOM_PREPROCESS_END = "wxCustomPreprocessEnd";
+
+    /************** stats *****************/
+    public static final String KEY_PAGE_STATS_BUNDLE_SIZE = "wxBundleSize";
+    public static final String KEY_PAGE_STATS_FS_CALL_JS_TIME = "wxFSCallJsTotalTime";
+    public static final String KEY_PAGE_STATS_FS_CALL_JS_NUM = "wxFSCallJsTotalNum";
+    public static final String KEY_PAGE_STATS_FS_TIMER_NUM = "wxFSTimerCount";
+    public static final String KEY_PAGE_STATS_FS_CALL_NATIVE_TIME = "wxFSCallNativeTotalTime";
+    public static final String KEY_PAGE_STATS_FS_CALL_NATIVE_NUM = "wxFSCallNativeTotalNum";
+    public static final String KEY_PAGE_STATS_FS_CALL_EVENT_NUM = "wxFSCallEventTotalNum";
+    public static final String KEY_PAGE_STATS_FS_REQUEST_NUM = "wxFSRequestNum";
+    public static final String KEY_PAGE_STATS_CELL_EXCEED_NUM = "wxCellExceedNum";
+    public static final String KEY_PAGE_STATS_MAX_DEEP_VIEW = "wxMaxDeepViewLayer";
+    public static final String KEY_PAGE_STATS_MAX_DEEP_DOM = "wxMaxDeepVDomLayer";
+    public static final String KEY_PAGE_STATS_MAX_COMPONENT_NUM = "wxMaxComponentCount";
+    public static final String KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT = "wxWrongImgSizeCount";
+    public static final String KEY_PAGE_STATS_EMBED_COUNT = "wxEmbedCount";
+    public static final String KEY_PAGE_STATS_LARGE_IMG_COUNT = "wxLargeImgMaxCount";
+    public static final String KEY_PAGE_STATS_BODY_RATIO = "wxBodyRatio";
+    public static final String KEY_PAGE_STATS_SCROLLER_NUM = "wxScrollerCount";
+    public static final String KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM = "wxCellDataUnRecycleCount";
+    public static final String KEY_PAGE_STATS_CELL_UN_RE_USE_NUM = "wxCellUnReUseCount";
+    public static final String KEY_PAGE_STATS_IMG_UN_RECYCLE_NUM = "wxImgUnRecycleCount";
+
+    public static final String KEY_PAGE_STATS_I_SCREEN_VIEW_COUNT = "wxInteractionScreenViewCount";
+    public static final String KEY_PAGE_STATS_I_ALL_VIEW_COUNT = "wxInteractionAllViewCount";
+    public static final String KEY_PAGE_STATS_I_COMPONENT_CREATE_COUNT = "wxInteractionComponentCreateCount";
+    public static final String KEY_PAGE_ANIM_BACK_NUM = "wxAnimationInBackCount";
+    public static final String KEY_PAGE_TIMER_BACK_NUM = "wxTimerInBackCount";
+    public static final String KEY_PAGE_STATS_ACTUAL_DOWNLOAD_TIME = "wxActualNetworkTime";
+
+    public static final String KEY_PAGE_STATS_IMG_LOAD_NUM = "wxImgLoadCount";
+    public static final String KEY_PAGE_STATS_IMG_LOAD_SUCCESS_NUM = "wxImgLoadSuccessCount";
+    public static final String KEY_PAGE_STATS_IMG_LOAD_FAIL_NUM = "wxImgLoadFailCount";
+    public static final String KEY_PAGE_STATS_NET_NUM = "wxNetworkRequestCount";
+    public static final String KEY_PAGE_STATS_NET_SUCCESS_NUM = "wxNetworkRequestSuccessCount";
+    public static final String KEY_PAGE_STATS_NET_FAIL_NUM = "wxNetworkRequestFailCount";
+    public static final String KEY_PAGE_STATS_JSLIB_INIT_TIME = "wxJSLibInitTime";
+    public static final String KEY_PAGE_STATS_VIEW_CREATE_COST = "wxViewCost";
+    public static final String KEY_PAGE_STATS_COMPONENT_CREATE_COST = "wxComponentCost";
+    public static final String KEY_PAGE_STATS_EXECUTE_JS_CALLBACK_COST = "wxExecJsCallBack";
+    public static final String KEY_PAGE_STATS_LAYOUT_TIME = "wxLayoutTime";
+
+
+    /************** value *****************/
+    public static final String VALUE_ERROR_CODE_DEFAULT = "0";
+    public static final String VALUE_BUNDLE_LOAD_LENGTH = "wxLoadedLength";
+
+    private String mInstanceId;
+    private IWXApmMonitorAdapter apmInstance;
+    private Map<String, Double> recordStatsMap;
+    public final Map<String, Long> stageMap;
+    private Map<String,Object> mPropertiesMap;
+    private boolean isFSEnd;
+    private boolean mHasInit = false;
+    private boolean mEnd = false;
+    private boolean hasRecordFistInteractionView =false;
+    public final Map<String,Object> extInfo;
+    public boolean forceStopRecordInteraction = false;
+    public Rect instanceRect;
+    public String reportPageName;
+    public boolean hasReportLayerOverDraw = false;
+    public boolean hasAddView;
+    private Handler mUIHandler;
+
+    public Set<String> exceptionRecord = new CopyOnWriteArraySet<String>();
+
+    private double interactionLayoutTime;
+    public long componentCreateTime;
+    private long interactionComponentCreateTime;
+    public long viewCreateTime;
+    private long interactionViewCreateTime;
+    //next version
+    private long wxExecJsCallBackTime;
+    private long interactionJsCallBackTime;
+
+
+    private boolean mHasRecordDetailData = false;
+
+    /**
+     * send performance value to js
+     **/
+    private boolean hasSendInteractionToJS = false;
+    public volatile boolean isReady = true;
+
+    public WXInstanceApm(String instanceId) {
+        mInstanceId = instanceId;
+        extInfo = new ConcurrentHashMap<>();
+        stageMap = new ConcurrentHashMap<>();
+        mUIHandler = new Handler(Looper.getMainLooper());
+        recordStatsMap = new ConcurrentHashMap<>();
+        mPropertiesMap = new ConcurrentHashMap<>();
+        IApmGenerator generator = WXSDKManager.getInstance().getApmGenerater();
+        if (null != generator) {
+            apmInstance = generator.generateApmInstance(WEEX_PAGE_TOPIC);
+        }
+    }
+
+    public void onInstanceReady(boolean isPreDownLoad){
+        this.isReady = true;
+        if (isPreDownLoad){
+            onStage(KEY_PAGE_STAGES_DOWN_BUNDLE_START);
+        }
+        doInit();
+        for (Map.Entry<String,Long> stage:stageMap.entrySet()){
+            sendStageInfo(stage.getKey(),stage.getValue());
+        }
+        for (Map.Entry<String,Double> stats:recordStatsMap.entrySet()){
+           sendStats(stats.getKey(),stats.getValue());
+        }
+        for (Map.Entry<String,Object> p:mPropertiesMap.entrySet()){
+           sendProperty(p.getKey(),p.getValue());
+        }
+    }
+
+    /**
+     * record event
+     */
+    public void onEvent(String name, Object value) {
+        if (null == apmInstance) {
+            return;
+        }
+        apmInstance.onEvent(name, value);
+    }
+
+    /**
+     * record stage
+     */
+    public void onStage(String name) {
+        long time =  WXUtils.getFixUnixTime();
+        onStageWithTime(name,time);
+    }
+
+    /**
+     *
+     * @param name stage
+     * @param time unixTime ,plz use WXUtils.getFixUnixTime
+     */
+    public void onStageWithTime(String name,long time){
+        if (mEnd){
+            return;
+        }
+        if (null == name){
+            return;
+        }
+        stageMap.put(name,time);
+        if (isReady){
+            sendStageInfo(name,time);
+        }
+    }
+
+    private void sendStageInfo(String name,long time){
+        if(WXAnalyzerDataTransfer.isOpenPerformance){
+            WXAnalyzerDataTransfer.transferPerformance(mInstanceId,"stage",name,time);
+        }
+
+        if (KEY_PAGE_STAGES_RENDER_ORGIGIN.equalsIgnoreCase(name)){
+            mUIHandler.postDelayed(jsPerformanceCallBack,8000);
+        }
+
+        if (null == apmInstance) {
+            return;
+        }
+
+        apmInstance.onStage(name, time);
+    }
+
+    private Runnable jsPerformanceCallBack = new Runnable() {
+        @Override
+        public void run() {
+            sendPerformanceToJS();
+        }
+    };
+
+    /**
+     * record property
+     */
+    public void addProperty(String key, Object value) {
+        if (mEnd){
+            return;
+        }
+        if (null == key || null == value){
+            return;
+        }
+        mPropertiesMap.put(key,value);
+        if (isReady){
+            sendProperty(key,value);
+        }
+    }
+
+    private void sendProperty(String key,Object value){
+        if(WXAnalyzerDataTransfer.isOpenPerformance){
+            WXAnalyzerDataTransfer.transferPerformance(mInstanceId,"properties",key,value);
+        }
+
+        if (null == apmInstance) {
+            return;
+        }
+        apmInstance.addProperty(key, value);
+    }
+
+    /**
+     * record statistic
+     */
+    public void addStats(String key, double value) {
+        if (mEnd){
+            return;
+        }
+        if (null == key){
+            return;
+        }
+        recordStatsMap.put(key,value);
+        if (isReady){
+            sendStats(key,value);
+        }
+    }
+
+    private void sendStats(String key,double value){
+        if(WXAnalyzerDataTransfer.isOpenPerformance){
+            WXAnalyzerDataTransfer.transferPerformance(mInstanceId,"stats",key,value);
+        }
+
+        if (null == apmInstance) {
+            return;
+        }
+        apmInstance.addStats(key, value);
+    }
+
+
+    public boolean hasInit(){
+        return mHasInit;
+    }
+
+    /**
+     * start record
+     */
+    public void doInit() {
+        if (!isReady){
+            return;
+        }
+        if (mHasInit){
+            return;
+        }
+        mHasInit = true;
+        if (null == apmInstance) {
+            return;
+        }
+        apmInstance.onStart(mInstanceId);
+        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(mInstanceId);
+        String url = null == instance ? "unKnowUrl" : instance.getBundleUrl();
+        addProperty(KEY_PAGE_PROPERTIES_BUBDLE_URL, url);
+        addProperty(KEY_PROPERTIES_ERROR_CODE, VALUE_ERROR_CODE_DEFAULT);
+        addProperty(KEY_PAGE_PROPERTIES_JSLIB_VERSION, WXEnvironment.JS_LIB_SDK_VERSION);
+        addProperty(KEY_PAGE_PROPERTIES_WEEX_VERSION, WXEnvironment.WXSDK_VERSION);
+        addProperty(KEY_PAGE_PROPERTIES_WEEX_VERSION, WXEnvironment.WXSDK_VERSION);
+        addStats("wxReInitCount", WXBridgeManager.reInitCount);
+        if (null != instance){
+            addProperty(KEY_PAGE_PROPERTIES_UIKIT_TYPE, instance.getRenderType());
+        }
+
+        addProperty("wxUseRuntimeApi",WXEnvironment.sUseRunTimeApi);
+        if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER
+                || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
+            addProperty(KEY_PAGE_PROPERTIES_RENDER_TYPE, WXEnvironment.EAGLE);
+        }
+        if (null != instance) {
+            for (Map.Entry<String, String> entry : instance.getContainerInfo().entrySet()) {
+                addProperty(entry.getKey(), entry.getValue());
+            }
+        }
+    }
+
+    public void setPageName(String pageName) {
+        if (TextUtils.isEmpty(pageName)) {
+            WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(mInstanceId);
+            if (null != instance) {
+                pageName = instance.getContainerInfo().get(KEY_PAGE_PROPERTIES_CONTAINER_NAME);
+            }
+        }
+        reportPageName = null == apmInstance?pageName:apmInstance.parseReportUrl(pageName);
+        reportPageName = TextUtils.isEmpty(reportPageName) ? "emptyPageName" : reportPageName;
+        addProperty(KEY_PAGE_PROPERTIES_BIZ_ID, reportPageName);
+    }
+
+    public void onAppear(){
+        if (null == apmInstance) {
+            return;
+        }
+        apmInstance.onAppear();
+    }
+
+    public void onDisAppear(){
+        if (null == apmInstance) {
+            return;
+        }
+        apmInstance.onDisappear();
+    }
+
+    /**
+     * end record
+     */
+    public void onEnd() {
+        if (null == apmInstance || mEnd) {
+            return;
+        }
+        new Handler(Looper.getMainLooper()).removeCallbacks(delayCollectDataTask);
+        recordPerformanceDetailData();
+        exceptionRecord.clear();
+        mUIHandler.removeCallbacks(jsPerformanceCallBack);
+        onStage(KEY_PAGE_STAGES_DESTROY);
+        if (mHasInit && null != apmInstance){
+            apmInstance.onEnd();
+        }
+        mEnd = true;
+        if (WXEnvironment.isApkDebugable()){
+            printLog();
+        }
+    }
+
+    public void doDelayCollectData(){
+        new Handler(Looper.getMainLooper()).postDelayed(delayCollectDataTask,8000);
+    }
+
+    private Runnable delayCollectDataTask = new Runnable() {
+        @Override
+        public void run() {
+            recordPerformanceDetailData();
+        }
+    };
+
+
+    private void printLog(){
+        Long startDownLoad = stageMap.get(KEY_PAGE_STAGES_DOWN_BUNDLE_START);
+        Long endDownLoad = stageMap.get(KEY_PAGE_STAGES_DOWN_BUNDLE_END);
+        Long interaction = stageMap.get(KEY_PAGE_STAGES_INTERACTION);
+        Long containerReady = stageMap.get(KEY_PAGE_STAGES_CONTAINER_READY);
+        if (null != endDownLoad && null != startDownLoad){
+            WXLogUtils.d("test->", "downLoadTime: "+ (endDownLoad - startDownLoad));
+        }
+        if (null != endDownLoad && null != interaction){
+            WXLogUtils.d("test->", "renderTime: "+ (interaction - endDownLoad));
+        }
+        if (null != containerReady && null !=interaction){
+            WXLogUtils.d("test->", "showTime: "+ (interaction - containerReady));
+        }
+
+    }
+
+    public void arriveNewFsRenderTime(){
+        if (null == apmInstance){
+            return;
+        }
+        onStage(WXInstanceApm.KEY_PAGE_STAGES_NEW_FSRENDER);
+    }
+
+    public void arriveFSRenderTime() {
+        if (null == apmInstance){
+            return;
+        }
+        isFSEnd = true;
+        onStage(WXInstanceApm.KEY_PAGE_STAGES_FSRENDER);
+    }
+
+    public void arriveInteraction(WXComponent targetComponent) {
+        if (null == apmInstance || null == targetComponent || targetComponent.getInstance() == null) {
+            return;
+        }
+
+        if (WXAnalyzerDataTransfer.isOpenPerformance){
+            WXAnalyzerDataTransfer.transferInteractionInfo(targetComponent);
+        }
+
+
+        if (null == apmInstance){
+            return;
+        }
+
+        WXPerformance performanceRecord = targetComponent.getInstance().getWXPerformance();
+        if (null == performanceRecord){
+            return;
+        }
+
+        long curTime = WXUtils.getFixUnixTime();
+
+        if (WXAnalyzerDataTransfer.isInteractionLogOpen()){
+            Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][wxinteraction]"
+                + targetComponent.getInstance().getInstanceId()
+                +","+targetComponent.getComponentType()
+                +","+targetComponent.getRef()
+                +","+targetComponent.getStyles()
+                +","+targetComponent.getAttrs()
+            );
+        }
+
+        if (!hasRecordFistInteractionView){
+            onStage(KEY_PAGE_STAGES_FIRST_INTERACTION_VIEW);
+            hasRecordFistInteractionView = true;
+        }
+        if (forceStopRecordInteraction){
+            return;
+        }
+        long now = WXUtils.getFixUnixTime();
+        if (now - preUpdateTime > 50){
+            //for performance, reduce jni calls
+            WXBridgeManager.getInstance().onInteractionTimeUpdate(mInstanceId);
+            preUpdateTime = now;
+        }
+
+        interactionComponentCreateTime = componentCreateTime;
+        interactionViewCreateTime = viewCreateTime;
+        Double layoutTime = recordStatsMap.get("wxLayoutTime");
+        interactionLayoutTime = layoutTime ==null? 0:layoutTime;
+
+        performanceRecord.interactionTime = curTime - performanceRecord.renderUnixTimeOrigin;
+        performanceRecord.interactionRealUnixTime = System.currentTimeMillis();
+        onStageWithTime(KEY_PAGE_STAGES_INTERACTION,curTime);
+
+        updateDiffStats(KEY_PAGE_STATS_I_SCREEN_VIEW_COUNT, 1);
+        updateMaxStats(KEY_PAGE_STATS_I_ALL_VIEW_COUNT, performanceRecord.localInteractionViewAddCount);
+        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
+        if (null != instance) {
+            updateMaxStats(KEY_PAGE_STATS_I_COMPONENT_CREATE_COUNT, instance.getWXPerformance().componentCount);
+        }
+    }
+
+    private long preUpdateTime = 0;
+
+    public void updateFSDiffStats(String name, double diffValue) {
+        if (null == apmInstance || isFSEnd) {
+            return;
+        }
+        updateDiffStats(name, diffValue);
+    }
+
+    public void recordPerformanceDetailData(){
+        if (mHasRecordDetailData){
+            return;
+        }
+        mHasRecordDetailData = true;
+        addStats(KEY_PAGE_STATS_VIEW_CREATE_COST,interactionViewCreateTime);
+        addStats(KEY_PAGE_STATS_COMPONENT_CREATE_COST,interactionComponentCreateTime);
+        addStats(KEY_PAGE_STATS_EXECUTE_JS_CALLBACK_COST,interactionJsCallBackTime);
+        addStats(KEY_PAGE_STATS_LAYOUT_TIME,interactionLayoutTime);
+    }
+
+    public void updateDiffStats(String name, double diffValue) {
+        if (null == apmInstance) {
+            return;
+        }
+        Double preVal = recordStatsMap.containsKey(name) ? recordStatsMap.get(name) : 0;
+        //fix by use ConcurrentHashMap,but not sure,so report if error still happen
+        if (null == preVal){
+            WXExceptionUtils.commitCriticalExceptionRT(
+                "",
+                WXErrorCode.WX_ERR_HASH_MAP_TMP,
+                "updateDiffStats",
+                "key : "+name,
+                null
+            );
+            return;
+        }
+
+        double currentValue = preVal + diffValue;
+        addStats(name, currentValue);
+    }
+
+    public void updateMaxStats(String name, double currentVal) {
+        if (null == apmInstance) {
+            return;
+        }
+        Double maxValue = recordStatsMap.containsKey(name) ? recordStatsMap.get(name) : 0;
+        //fix by use ConcurrentHashMap,but not sure,so report if error still happen
+        if (null == maxValue){
+            WXExceptionUtils.commitCriticalExceptionRT(
+                "",
+                WXErrorCode.WX_ERR_HASH_MAP_TMP,
+                "updateMaxStats",
+                "key : "+name,
+                null
+            );
+            return;
+        }
+        if (maxValue < currentVal) {
+            maxValue = currentVal;
+            addStats(name, maxValue);
+        }
+    }
+
+    public void updateRecordInfo(Map<String, Object> extParams) {
+        if (null == apmInstance || null == extParams) {
+            return;
+        }
+
+        addPropeyFromExtParms(KEY_PAGE_PROPERTIES_REQUEST_TYPE, KEY_PAGE_PROPERTIES_REQUEST_TYPE, extParams);
+        addPropeyFromExtParms("cacheType", KEY_PAGE_PROPERTIES_CACHE_TYPE, extParams);
+        addPropeyFromExtParms("zCacheInfo", KEY_PAGE_PROPERTIES_CACHE_INFO, extParams);
+
+        addStats(KEY_PAGE_STATS_JSLIB_INIT_TIME, WXEnvironment.sJSLibInitTime);
+        addProperty(KEY_PAGE_PROPERTIES_JS_FM_INI, WXEnvironment.JsFrameworkInit);
+
+        Object wxNetLibDownBundleTime = extParams.get("actualNetworkTime");
+        if (wxNetLibDownBundleTime instanceof Long) {
+            updateDiffStats(KEY_PAGE_STATS_ACTUAL_DOWNLOAD_TIME, ((Long)wxNetLibDownBundleTime).doubleValue());
+        }
+    }
+
+    private void addPropeyFromExtParms(String fromKey, String toKey, Map<String, Object> extParams) {
+        Object value = extParams.get(fromKey);
+        if (value instanceof String) {
+            addProperty(toKey, value);
+        }
+    }
+
+    /************** called by IWXHttpAdapter implementer *****************/
+
+    public void actionNetRequest() {
+        if (!isFSEnd) {
+            updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_REQUEST_NUM, 1);
+        }
+        updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_NET_NUM, 1);
+    }
+
+    public void actionNetResult(boolean succeed, String errorCode) {
+        if (succeed) {
+            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_NET_SUCCESS_NUM, 1);
+        } else {
+            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_NET_FAIL_NUM, 1);
+        }
+    }
+
+    /************** called by IWXImgLoaderAdapter implementer *****************/
+
+    public void actionLoadImg() {
+        updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_LOAD_NUM, 1);
+    }
+
+    public void actionLoadImgResult(boolean succeed, String errorCode) {
+        if (succeed) {
+            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_LOAD_SUCCESS_NUM, 1);
+        } else {
+            updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_LOAD_FAIL_NUM, 1);
+        }
+    }
+
+    public void sendPerformanceToJS() {
+        if (hasSendInteractionToJS) {
+            return;
+        }
+        hasSendInteractionToJS = true;
+        WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(mInstanceId);
+        if (null == instance) {
+            return;
+        }
+
+        Map<String,String> sendProperties = new HashMap<>(2);
+        sendProperties.put(KEY_PAGE_PROPERTIES_BIZ_ID,reportPageName);
+        sendProperties.put(KEY_PAGE_PROPERTIES_BUBDLE_URL,instance.getBundleUrl());
+
+        Map<String,Long> sendStage = new HashMap<>(1);
+        sendStage.put(KEY_PAGE_STAGES_INTERACTION,instance.getWXPerformance().interactionRealUnixTime);
+
+        Map<String, Object> data = new HashMap<>(2);
+        data.put("stage",sendStage);
+        data.put("properties",sendProperties);
+
+        instance.fireGlobalEventCallback("wx_apm", data);
+    }
+
+
+    public String toPerfString() {
+        Long start = stageMap.get(KEY_PAGE_STAGES_RENDER_ORGIGIN);
+        Long end = stageMap.get(KEY_PAGE_STAGES_INTERACTION);
+        Long wxNewFsRender = stageMap.get(KEY_PAGE_STAGES_NEW_FSRENDER);
+        StringBuilder builder = new StringBuilder();
+        if(start != null && end != null){
+            builder.append("interactiveTime " + (end - start) + "ms");
+        }
+        if(wxNewFsRender != null){
+            builder.append(" wxNewFsRender " + (wxNewFsRender) + "ms");
+        }
+        return builder.toString();
+   }
+
+   public void updateNativePerformanceData(Map<String,String> nativePerformanceData){
+        if (null == nativePerformanceData){
+            return;
+        }
+        for (Map.Entry<String,String> entry : nativePerformanceData.entrySet()){
+            double value = -1;
+            try {
+                value = Double.valueOf(entry.getValue());
+            }catch (Exception e){
+                e.printStackTrace();
+            }
+            if (value != -1){
+                recordStatsMap.put(entry.getKey(),value);
+            }
+        }
+   }
+ }
diff --git a/android/sdk/src/main/java/org/apache/weex/performance/WXStateRecord.java b/android/sdk/src/main/java/org/apache/weex/performance/WXStateRecord.java
new file mode 100644
index 0000000..00328ff
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/performance/WXStateRecord.java
@@ -0,0 +1,209 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.performance;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import android.support.annotation.NonNull;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.utils.WXUtils;
+
+/**
+ * @author zhongcang
+ * @date 2019/6/19
+ */
+public class WXStateRecord {
+
+    private RecordList<Info> mExceptionHistory;
+    private RecordList<Info> mActionHistory;
+    private RecordList<Info> mJsfmInitHistory;
+    private RecordList<Info> mJscCrashHistory;
+    private RecordList<Info> mJscReloadHistory;
+    private RecordList<Info> mJsThradWatchHistory;
+    private RecordList<Info> mIPCExceptionHistory;
+
+    private static class SingleTonHolder {
+        private static final WXStateRecord S_INSTANCE = new WXStateRecord();
+    }
+
+    public static WXStateRecord getInstance() {
+        return SingleTonHolder.S_INSTANCE;
+    }
+
+    private WXStateRecord() {
+        mExceptionHistory = new RecordList<>(10);
+        mActionHistory = new RecordList<>(20);
+        mJsfmInitHistory = new RecordList<>(10);
+        mJscCrashHistory = new RecordList<>(10);
+        mJscReloadHistory = new RecordList<>(10);
+        mJsThradWatchHistory = new RecordList<>(20);
+        mIPCExceptionHistory = new RecordList<>(20);
+    }
+
+    /**
+     * check history exception (may be cause ws)
+     */
+    public void recordException(String instanceId, String exception) {
+        String shortException = exception.length() > 200 ?exception.substring(0,200) : exception;
+        recordCommon(mExceptionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, shortException));
+    }
+
+    /**
+     * check history action (may be occupy cpu by preInstance or some task)
+     */
+    public void recordAction(String instanceId, String action) {
+        recordCommon(mActionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, action));
+    }
+
+    public void recordIPCException (String instanceId,String exception){
+        String shortException = exception.length() > 200 ?exception.substring(0,200) : exception;
+        recordCommon(mIPCExceptionHistory,new Info(WXUtils.getFixUnixTime(), instanceId, shortException));
+    }
+
+    /**
+     * check onJSFMInit time,and we know when jsfm is init sucess in reloadJsEngine case
+     */
+    public void onJSFMInit() {
+        recoreJsfmInitHistory("setJsfmVersion");
+    }
+
+    public void recoreJsfmInitHistory(String msg){
+        recordCommon(mJsfmInitHistory,new Info(WXUtils.getFixUnixTime(), "JSFM", msg));
+    }
+
+    public void recordJsThreadWatch(String msg){
+        recordCommon(mJsThradWatchHistory,new Info(WXUtils.getFixUnixTime(), "jsWatch", msg));
+    }
+
+    /**
+     * check onJSEngineReload time,and we know how many times reload and each reload time
+     */
+    public void onJSEngineReload(String instanceId) {
+        recordCommon(mJscReloadHistory,new Info(WXUtils.getFixUnixTime(), instanceId, "onJSEngineReload"));
+    }
+
+    /**
+     * check jsc crash time,and we know how many times jscCrash and each crash time
+     */
+    public void onJSCCrash(String instanceId) {
+        recordCommon(mJscCrashHistory,new Info(WXUtils.getFixUnixTime(), instanceId, "onJSCCrash"));
+    }
+
+    private void recordCommon(RecordList<Info> list ,Info info){
+        if (null == list || null == info){
+            return;
+        }
+        try {
+            list.add(info);
+            if (!list.isEmpty() && list.size()>list.maxSize){
+                list.poll();
+            }
+        }catch (Throwable e){
+            e.getStackTrace();
+        }
+    }
+
+    public Map<String, String> getStateInfo() {
+        Map<String, String> stateInfo = new HashMap<>(5);
+        stateInfo.put("reInitCount", String.valueOf(WXBridgeManager.reInitCount));
+
+        int size = mExceptionHistory.size()+mActionHistory.size()+mJsfmInitHistory.size()
+            +mJscCrashHistory.size()+mJscReloadHistory.size()+mJsThradWatchHistory.size();
+
+        List<Info> reportTimeLineInfo = new ArrayList<>(size);
+        reportTimeLineInfo.addAll(mExceptionHistory);
+        reportTimeLineInfo.addAll(mActionHistory);
+        reportTimeLineInfo.addAll(mJsfmInitHistory);
+        reportTimeLineInfo.addAll(mJscCrashHistory);
+        reportTimeLineInfo.addAll(mJscReloadHistory);
+        reportTimeLineInfo.addAll(mJsThradWatchHistory);
+        reportTimeLineInfo.addAll(mIPCExceptionHistory);
+        Collections.sort(reportTimeLineInfo);
+        stateInfo.put("stateInfoList",reportTimeLineInfo.toString());
+
+        IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+        if (null != adapter && "true".equalsIgnoreCase(adapter.getConfig("wxapm","dumpIpcPageInfo","true"))){
+            stateInfo.put("pageQueueInfo",WXBridgeManager.getInstance().dumpIpcPageInfo());
+        }
+        return stateInfo;
+    }
+
+    private static class RecordList<E> extends ConcurrentLinkedQueue<E> {
+        private int maxSize;
+
+        public RecordList(int maxSize) {
+            super();
+            this.maxSize = maxSize;
+        }
+    }
+
+    private static class Info implements Comparable<Info>{
+        private long time;
+        private String instanceId;
+        private String msg;
+
+        public Info(long time, String instance, String msg) {
+            this.time = time;
+            this.instanceId = instance;
+            this.msg = msg;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                .append('[').append(instanceId).append(',').append(time).append(',').append(msg).append("]->")
+                .toString();
+        }
+
+        @Override
+        public int compareTo(@NonNull Info next) {
+            if (this.time == next.time){
+                return 0;
+            }
+            return this.time > next.time? 1:-1;
+        }
+    }
+
+    public void startJSThreadWatchDog(){
+        WXBridgeManager.getInstance().post(jsThreadWatchTask);
+    }
+
+    private  long jsThreadTime =-1;
+
+    private Runnable jsThreadWatchTask = new Runnable() {
+        @Override
+        public void run() {
+            if (jsThreadTime == -1){
+                jsThreadTime = WXUtils.getFixUnixTime();
+            }
+            long diff = WXUtils.getFixUnixTime() - jsThreadTime;
+            recordJsThreadWatch("diff:"+diff);
+            jsThreadTime = WXUtils.getFixUnixTime();
+            WXBridgeManager.getInstance().postDelay(jsThreadWatchTask,500);
+        }
+    };
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/performance/WhiteScreenUtils.java b/android/sdk/src/main/java/org/apache/weex/performance/WhiteScreenUtils.java
new file mode 100644
index 0000000..0ea349c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/performance/WhiteScreenUtils.java
@@ -0,0 +1,176 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.performance;
+
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.utils.WXViewUtils;
+import org.json.JSONObject;
+
+/**
+ * @author zhongcang
+ * @date 2019/5/30
+ */
+public class WhiteScreenUtils {
+
+    public static boolean doWhiteScreenCheck() {
+        IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
+        if (null == configAdapter) {
+            return false;
+        }
+        double randomValue = Math.random() * 100;
+        double max = 100;
+        try {
+            String configValue = configAdapter.getConfig("wxapm", "new_ws_sampling", "100");
+            max = Double.valueOf(configValue);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return randomValue < max;
+    }
+
+    public static boolean isWhiteScreen(WXSDKInstance instance) {
+        if (null == instance) {
+            return false;
+        }
+        View v = instance.getContainerView();
+        if (!(v instanceof ViewGroup)) {
+            return false;
+        }
+
+        if (!WXViewUtils.isViewVisible(v) || !checkParentVisible(v.getParent())){
+            return false;
+        }
+        if (isInWhiteList(instance)){
+            return false;
+        }
+        return !hasLeafViewOrSizeIgnore(v,3);
+    }
+
+    private static boolean isInWhiteList(WXSDKInstance instance){
+        IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
+        if (null == configAdapter){
+            return false;
+        }
+        String whiteList = configAdapter.getConfig("wxapm","ws_white_list",null);
+        if (TextUtils.isEmpty(whiteList)){
+            return false;
+        }
+        try {
+            String[] urlList = whiteList.split(";");
+            for (String whiteUrl : urlList){
+                if (instance.getBundleUrl() != null && instance.getBundleUrl().contains(whiteUrl)){
+                    return true;
+                }
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+        return false;
+    }
+
+    private static boolean checkParentVisible(ViewParent parent){
+        //root view getParent is null
+        if (!(parent instanceof View)){
+            return true;
+        }
+        View vp = (View)parent;
+        boolean visible = vp.getVisibility() == View.VISIBLE && vp.getAlpha()>0;
+        if (!visible){
+            return false;
+        }
+        return checkParentVisible(vp.getParent());
+    }
+
+    private static boolean hasLeafViewOrSizeIgnore(View v,int checkDeep) {
+
+        if (!(v instanceof ViewGroup)) {
+            return true;
+        }
+
+        if (checkDeep > 0){
+            if ( v.getHeight() < 10 || v.getWidth() < 10) {
+                return true;
+            }
+            checkDeep--;
+        }
+
+        ViewGroup group = (ViewGroup)v;
+        for (int i = 0; i < group.getChildCount(); i++) {
+            View child = group.getChildAt(i);
+            boolean res = hasLeafViewOrSizeIgnore(child,checkDeep);
+            if (res) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * get instance viewTree && component tree msg
+     */
+    public static String takeViewTreeSnapShot(WXSDKInstance instance) {
+        if (null == instance) {
+            return "nullInstance";
+        }
+        View v = instance.getContainerView();
+        JSONObject root = geViewDetailTreeMsg(v);
+        if (null != root) {
+            return root.toString();
+        }
+        return "";
+    }
+
+    private static JSONObject geViewDetailTreeMsg(View view) {
+        if (null == view) {
+            return null;
+        }
+        JSONObject node = new JSONObject();
+        try {
+            node.put("width", view.getWidth());
+            node.put("height", view.getHeight());
+            int[] location = new int[2];
+            location[0] = -1;
+            location[1] = -1;
+            view.getLocationOnScreen(location);
+            node.put("x", location[0]);
+            node.put("y", location[1]);
+
+            if (view instanceof ViewGroup) {
+                node.put("type", view.getClass().getSimpleName());
+                ViewGroup group = (ViewGroup)view;
+                for (int i = 0; i < group.getChildCount(); i++) {
+                    node.put("child_"+i, geViewDetailTreeMsg(group.getChildAt(i)));
+                }
+            } else {
+                node.put("type", view.getClass().getSimpleName());
+            }
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return node;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/render/WXAbstractRenderContainer.java b/android/sdk/src/main/java/org/apache/weex/render/WXAbstractRenderContainer.java
new file mode 100644
index 0000000..2fc3192
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/render/WXAbstractRenderContainer.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.render;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+import org.apache.weex.WXSDKInstance;
+import java.lang.ref.WeakReference;
+
+public class WXAbstractRenderContainer extends FrameLayout {
+
+    protected  WeakReference<WXSDKInstance> mSDKInstance;
+    protected boolean mHasConsumeEvent = false;
+
+    public WXAbstractRenderContainer(@NonNull Context context) {
+        super(context);
+    }
+
+    public WXAbstractRenderContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public WXAbstractRenderContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public WXAbstractRenderContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public void setSDKInstance(WXSDKInstance instance) {
+        mSDKInstance = new WeakReference<>(instance);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        WXSDKInstance instance;
+        if (mSDKInstance != null && (instance = mSDKInstance.get()) != null) {
+            //re-render instance
+            instance.setSize(w, h);
+        }
+    }
+
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        mHasConsumeEvent = true;
+        return super.dispatchTouchEvent(ev);
+    }
+
+    public boolean hasConsumeEvent(){
+        return mHasConsumeEvent;
+    }
+
+    public void createInstanceRenderView(String instanceId){
+
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/tracing/Stopwatch.java b/android/sdk/src/main/java/org/apache/weex/tracing/Stopwatch.java
new file mode 100644
index 0000000..83f2f55
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/tracing/Stopwatch.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.tracing;
+
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created by moxun on 2017/6/2.
+ */
+
+public class Stopwatch {
+  private static final ThreadLocal<Stopwatch> sThreadLocal = new ThreadLocal<>();
+  private long startNanos;
+  private List<ProcessEvent> splits = new ArrayList<>();
+  private long startMillis;
+
+  private static void prepare() {
+    if (sThreadLocal.get() == null) {
+      sThreadLocal.set(new Stopwatch());
+    }
+  }
+
+  public static void tick() {
+    if (WXTracing.isAvailable()) {
+      try {
+        prepare();
+        if (sThreadLocal.get().startNanos != 0L) {
+          WXLogUtils.w("Stopwatch", "Stopwatch is not reset");
+        }
+        sThreadLocal.get().startNanos = System.nanoTime();
+        sThreadLocal.get().startMillis = System.currentTimeMillis();
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+    }
+  }
+
+  public static void split(String fname) {
+    if (WXTracing.isAvailable()) {
+      try {
+        ProcessEvent event = new ProcessEvent();
+        long start = sThreadLocal.get().startMillis;
+        double millis = tackAndTick();
+        event.fname = fname;
+        event.duration = millis;
+        event.startMillis = start;
+        sThreadLocal.get().splits.add(event);
+      } catch (Throwable throwable) {
+        throwable.printStackTrace();
+      }
+    }
+  }
+
+  public static List<ProcessEvent> getProcessEvents() {
+    if (WXTracing.isAvailable()) {
+      tack();
+      List<ProcessEvent> existedEvents = sThreadLocal.get().splits;
+      sThreadLocal.get().splits = new ArrayList<>();
+      return existedEvents;
+    } else {
+      return Collections.emptyList();
+    }
+  }
+
+  public static double tack() {
+    if (WXTracing.isAvailable()) {
+      try {
+        long startNanos = sThreadLocal.get().startNanos;
+        if (startNanos == 0L) {
+          WXLogUtils.w("Stopwatch", "Should call Stopwatch.tick() before Stopwatch.tack() called");
+        }
+        long nanos = System.nanoTime() - startNanos;
+        sThreadLocal.get().startNanos = 0L;
+        return nanosToMillis(nanos);
+      } catch (Throwable throwable) {
+        throwable.printStackTrace();
+      }
+    }
+    return -1;
+  }
+
+  public static long lastTickStamp() {
+    if (WXTracing.isAvailable()) {
+      try {
+        return sThreadLocal.get().startMillis;
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+    }
+    return -1;
+  }
+
+  public static double tackAndTick() {
+    double ms = tack();
+    tick();
+    return ms;
+  }
+
+  public static double nanosToMillis(long nanos) {
+    return nanos / 1000000.0;
+  }
+
+  public static double millisUntilNow(long startNanos) {
+    return nanosToMillis(System.nanoTime() - startNanos);
+  }
+
+  public static class ProcessEvent {
+    public String fname;
+    public double duration;
+    public long startMillis;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/tracing/WXTracing.java b/android/sdk/src/main/java/org/apache/weex/tracing/WXTracing.java
new file mode 100644
index 0000000..834fb1c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/tracing/WXTracing.java
@@ -0,0 +1,129 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.tracing;
+
+import android.os.Looper;
+import android.util.SparseArray;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.ITracingAdapter;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Created by moxun on 2017/6/6.
+ */
+
+public class WXTracing {
+  private static final AtomicInteger sIdGenerator = new AtomicInteger(0);
+
+  public static int nextId() {
+    return sIdGenerator.getAndIncrement();
+  }
+
+  public static boolean isAvailable() {
+    return WXEnvironment.isApkDebugable();
+  }
+
+  public static synchronized void submit(TraceEvent event) {
+    ITracingAdapter tracingAdapter = WXSDKManager.getInstance().getTracingAdapter();
+    if (tracingAdapter != null) {
+      tracingAdapter.submitTracingEvent(event);
+    }
+  }
+
+  public static class TraceEvent {
+    public String fname;
+    public String tname;
+    public String ph;
+    public int traceId;
+    public long ts;
+    public String iid;
+    public String ref;
+    public String parentRef;
+    public String name;
+    public String classname;
+    public int parentId = -1;
+    public double duration;
+
+    /**
+     * Internal use
+     */
+    public SparseArray<TraceEvent> subEvents;
+    public String payload;
+    public double parseJsonTime;
+    public boolean isSegment;
+    public Map<String, Object> extParams;
+    public boolean firstScreenFinish;
+
+    private boolean submitted;
+
+    public TraceEvent() {
+      ts = System.currentTimeMillis();
+      traceId = nextId();
+      tname = currentThreadName();
+    }
+
+    public void submit() {
+      if (!submitted) {
+        submitted = true;
+        WXTracing.submit(this);
+      } else {
+        WXLogUtils.w("WXTracing", "Event " + traceId + " has been submitted.");
+      }
+    }
+  }
+
+  public static String currentThreadName() {
+    Thread thread = Thread.currentThread();
+    String name = thread.getName();
+
+    if ("WeexJSBridgeThread".equals(name)) {
+      return "JSThread";
+    } else if ("WeeXDomThread".equals(name)) {
+      return "DOMThread";
+    } else if (Looper.getMainLooper() == Looper.myLooper()) {
+      return "UIThread";
+    }
+
+    return name;
+  }
+
+  public static TraceEvent newEvent(String fname, String instanceId, int parentId) {
+    WXTracing.TraceEvent traceEvent = new TraceEvent();
+    traceEvent.fname = fname;
+    traceEvent.iid = instanceId;
+    traceEvent.traceId = WXTracing.nextId();
+    traceEvent.parentId = parentId;
+    return traceEvent;
+  }
+
+  public static class TraceInfo {
+    public int rootEventId;
+    public long domQueueTime;
+    public long uiQueueTime;
+    public long domThreadStart = -1;
+    public long domThreadNanos;
+    public long uiThreadStart = -1;
+    public long uiThreadNanos;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/ComponentCreator.java b/android/sdk/src/main/java/org/apache/weex/ui/ComponentCreator.java
new file mode 100644
index 0000000..c249182
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/ComponentCreator.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Created by sospartan on 7/27/16.
+ */
+public interface ComponentCreator {
+  WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/ExternalLoaderComponentHolder.java b/android/sdk/src/main/java/org/apache/weex/ui/ExternalLoaderComponentHolder.java
new file mode 100644
index 0000000..1b2c680
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/ExternalLoaderComponentHolder.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import android.util.Pair;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.bridge.Invoker;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by sospartan on 8/26/16.
+ */
+public class ExternalLoaderComponentHolder implements IFComponentHolder {
+  public static final String TAG = "SimpleComponentHolder";
+  private Map<String, Invoker> mPropertyInvokers;
+  private Map<String, Invoker> mMethodInvokers;
+  private final IExternalComponentGetter mClzGetter;
+  private final String mType;
+  private Class mClass;
+
+
+  public ExternalLoaderComponentHolder(String type,IExternalComponentGetter clzGetter) {
+    this.mClzGetter = clzGetter;
+    mType = type;
+  }
+
+  @Override
+  public void loadIfNonLazy() {
+  }
+
+  private synchronized boolean generate(){
+    if(mClass==null){
+      return false;
+    }
+
+    Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = SimpleComponentHolder.getMethods(mClass);
+    mPropertyInvokers = methodPair.first;
+    mMethodInvokers = methodPair.second;
+    return true;
+  }
+
+  @Override
+  public synchronized WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+    if (mClass == null) {
+      mClass = mClzGetter.getExternalComponentClass(mType, instance);
+    }
+    ComponentCreator creator = new SimpleComponentHolder.ClazzComponentCreator(mClass);
+    WXComponent component = creator.createInstance(instance, parent, basicComponentData);
+
+    component.bindHolder(this);
+    return component;
+  }
+
+  @Override
+  public synchronized Invoker getPropertyInvoker(String name){
+    if (mPropertyInvokers == null && !generate()) {
+      return null;
+    }
+
+    return mPropertyInvokers.get(name);
+  }
+
+  @Override
+  public Invoker getMethodInvoker(String name) {
+    if(mMethodInvokers == null && !generate()){
+      return null;
+    }
+    return mMethodInvokers.get(name);
+  }
+
+  @Override
+  public synchronized String[] getMethods() {
+    if(mMethodInvokers == null && !generate()){
+      //generate failed
+      return new String[0];
+    }
+    Set<String> keys = mMethodInvokers.keySet();
+    return keys.toArray(new String[keys.size()]);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/IExternalComponentGetter.java b/android/sdk/src/main/java/org/apache/weex/ui/IExternalComponentGetter.java
new file mode 100644
index 0000000..d78f535
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/IExternalComponentGetter.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by zhengshihan on 16/8/25.
+ */
+public interface IExternalComponentGetter {
+    Class<? extends WXComponent> getExternalComponentClass(String type, WXSDKInstance instance);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/IExternalModuleGetter.java b/android/sdk/src/main/java/org/apache/weex/ui/IExternalModuleGetter.java
new file mode 100644
index 0000000..bc7ca92
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/IExternalModuleGetter.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import android.content.Context;
+
+import org.apache.weex.common.WXModule;
+
+/**
+ * Created by zhengshihan on 16/8/25.
+ */
+public interface IExternalModuleGetter {
+    Class<? extends WXModule> getExternalModuleClass(String type, Context context);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/IFComponentHolder.java b/android/sdk/src/main/java/org/apache/weex/ui/IFComponentHolder.java
new file mode 100644
index 0000000..d3a21f2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/IFComponentHolder.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import org.apache.weex.bridge.Invoker;
+import org.apache.weex.bridge.JavascriptInvokable;
+
+/**
+ * Created by sospartan on 6/23/16.
+ */
+public interface IFComponentHolder extends ComponentCreator, JavascriptInvokable {
+
+    /** Prepare component if not a lazy load componnet.**/
+    void loadIfNonLazy();
+
+    Invoker getPropertyInvoker(String name);
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/RenderContextImpl.java b/android/sdk/src/main/java/org/apache/weex/ui/RenderContextImpl.java
new file mode 100644
index 0000000..fe9d0e6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/RenderContextImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.dom.RenderContext;
+import org.apache.weex.ui.component.WXComponent;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Class for rendering view. Method in this class should be run in main thread.
+ * This class is also <strong>not</storng> thread safe.
+ */
+class RenderContextImpl implements RenderContext {
+
+  private Map<String, WXComponent> mRegistry;
+  private WXSDKInstance mWXSDKInstance;
+
+  public RenderContextImpl(WXSDKInstance instance) {
+    mWXSDKInstance = instance;
+    mRegistry = new ConcurrentHashMap<>();
+  }
+
+  public void destroy() {
+    mWXSDKInstance = null;
+    try {
+      mRegistry.clear();
+    } catch (Throwable e) {
+      e.printStackTrace();
+    }
+  }
+
+  public WXSDKInstance getWXSDKInstance() {
+    return mWXSDKInstance;
+  }
+
+  @Override
+  public WXSDKInstance getInstance() {
+    return mWXSDKInstance;
+  }
+
+  @Override
+  public WXComponent getComponent(String ref) {
+    return mRegistry.get(ref);
+  }
+
+  public void registerComponent(String ref, WXComponent comp) {
+    mRegistry.put(ref, comp);
+  }
+
+  @Override
+  public WXComponent unregisterComponent(String ref) {
+    return mRegistry.remove(ref);
+  }
+
+  public int getComponentCount(){
+    return mRegistry.size();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/SimpleComponentHolder.java b/android/sdk/src/main/java/org/apache/weex/ui/SimpleComponentHolder.java
new file mode 100644
index 0000000..48c78ef
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/SimpleComponentHolder.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import android.util.Pair;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.Invoker;
+import org.apache.weex.bridge.MethodInvoker;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXComponentProp;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.weex.bridge.WXBridgeManager;
+
+/**
+ * Created by sospartan on 6/12/16.
+ */
+public class SimpleComponentHolder implements IFComponentHolder{
+  public static final String TAG = "SimpleComponentHolder";
+  private final Class<? extends WXComponent> mClz;
+  private Map<String, Invoker> mPropertyInvokers;
+  private Map<String, Invoker> mMethodInvokers;
+  private ComponentCreator mCreator;
+
+  public static class ClazzComponentCreator implements ComponentCreator{
+
+    private Constructor<? extends WXComponent> mConstructor;
+    private final Class<? extends WXComponent> mCompClz;
+
+    public ClazzComponentCreator(Class<? extends WXComponent> c){
+      mCompClz = c;
+    }
+
+    private void loadConstructor() {
+      Class<? extends WXComponent> c = mCompClz;
+      Constructor<? extends WXComponent> constructor;
+      try {
+        constructor = c.getConstructor(WXSDKInstance.class, WXVContainer.class, BasicComponentData.class);
+      } catch (NoSuchMethodException e) {
+        WXLogUtils.d("ClazzComponentCreator", "Use deprecated component constructor");
+        try {
+          //compatible deprecated constructor with 4 args
+          constructor = c.getConstructor(WXSDKInstance.class, WXVContainer.class, boolean.class, BasicComponentData.class);
+        } catch (NoSuchMethodException e1) {
+          try {
+            //compatible deprecated constructor with 5 args
+            constructor = c.getConstructor(WXSDKInstance.class, WXVContainer.class, String.class, boolean.class, BasicComponentData.class);
+          } catch (NoSuchMethodException e2) {
+            throw new WXRuntimeException("Can't find constructor of component.");
+          }
+        }
+      }
+      mConstructor = constructor;
+    }
+
+    @Override
+    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      if(mConstructor == null){
+        loadConstructor();
+      }
+      int parameters = mConstructor.getParameterTypes().length;
+      WXComponent component;
+
+      if(parameters == 3){
+        component =  mConstructor.newInstance(instance,parent, basicComponentData);
+      }else if(parameters == 4){
+        component =  mConstructor.newInstance(instance,parent,false, basicComponentData);
+      }else{
+        //compatible deprecated constructor
+        component =  mConstructor.newInstance(instance,parent,instance.getInstanceId(),parent.isLazy());
+      }
+      return component;
+    }
+  }
+
+  public SimpleComponentHolder(Class<? extends WXComponent> clz) {
+    this(clz,new ClazzComponentCreator(clz));
+  }
+
+  public SimpleComponentHolder(Class<? extends WXComponent> clz,ComponentCreator customCreator) {
+    this.mClz = clz;
+    this.mCreator = customCreator;
+  }
+
+  @Override
+  public void loadIfNonLazy() {
+    Annotation[] annotations = mClz.getDeclaredAnnotations();
+    for (Annotation annotation :
+      annotations) {
+      if (annotation instanceof Component){
+        if(!((Component) annotation).lazyload() && mMethodInvokers == null){
+          generate();
+        }
+        return;
+      }
+    }
+  }
+
+  private synchronized void generate(){
+    if(WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d(TAG, "Generate Component:" + mClz.getSimpleName());
+    }
+
+    Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = getMethods(mClz);
+    mPropertyInvokers = methodPair.first;
+    mMethodInvokers = methodPair.second;
+  }
+
+  public static Pair<Map<String,Invoker>,Map<String,Invoker>> getMethods(Class clz){
+    Map<String, Invoker> methods = new HashMap<>();
+    Map<String, Invoker> mInvokers = new HashMap<>();
+
+    Annotation[] annotations;
+    Annotation anno;
+    try {
+      for (Method method : clz.getMethods()) {
+        try {
+          annotations = method.getDeclaredAnnotations();
+          for (int i = 0, annotationsCount = annotations.length;
+               i < annotationsCount; ++i) {
+            anno = annotations[i];
+            if(anno == null){
+              continue;
+            }
+            if (anno instanceof WXComponentProp) {
+              String name = ((WXComponentProp) anno).name();
+              methods.put(name, new MethodInvoker(method,true));
+              break;
+            }else if(anno instanceof JSMethod){
+              JSMethod methodAnno = (JSMethod)anno;
+              String name = methodAnno.alias();
+              if(JSMethod.NOT_SET.equals(name)){
+                name = method.getName();
+              }
+              mInvokers.put(name, new MethodInvoker(method,methodAnno.uiThread()));
+              break;
+            }
+          }
+        } catch (ArrayIndexOutOfBoundsException | IncompatibleClassChangeError e) {
+          //ignore: getDeclaredAnnotations may throw this
+        }
+      }
+    }catch (IndexOutOfBoundsException e){
+      e.printStackTrace();
+      //ignore: getMethods may throw this
+    }catch (Exception e){ // in meizhu mobile, throw class not found exception in getMethods
+      WXLogUtils.e(TAG, e);
+    }
+    return new Pair<>(methods,mInvokers);
+  }
+
+
+
+  @Override
+  public synchronized WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+    WXComponent component = mCreator.createInstance(instance, parent, basicComponentData);
+
+    component.bindHolder(this);
+    return component;
+  }
+
+  @Override
+  public synchronized Invoker getPropertyInvoker(String name){
+      if (mPropertyInvokers == null) {
+        generate();
+      }
+
+    return mPropertyInvokers.get(name);
+  }
+
+  @Override
+  public Invoker getMethodInvoker(String name) {
+    if(mMethodInvokers == null){
+      generate();
+    }
+    return mMethodInvokers.get(name);
+  }
+
+  @Override
+  public synchronized String[] getMethods() {
+    if(mMethodInvokers == null){
+      generate();
+    }
+    Set<String> keys = mMethodInvokers.keySet();
+    try {
+      return keys.toArray(new String[keys.size()]);
+    } catch (Throwable throwable) {
+      if(mClz != null) {
+        String name = mClz.getName();
+        String errorMsg = name + ": gen methods failed";
+        WXExceptionUtils.commitCriticalExceptionRT(null,
+                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT,
+                WXBridgeManager.METHOD_REGISTER_COMPONENTS, errorMsg,
+                null);
+      }
+
+      return new String[1];
+    }
+
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/WXComponentRegistry.java b/android/sdk/src/main/java/org/apache/weex/ui/WXComponentRegistry.java
new file mode 100644
index 0000000..eee9be0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/WXComponentRegistry.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.WXException;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.cache.RegisterCache;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.weex.utils.cache.RegisterCache.ComponentCache;
+
+/**
+ * All components must be registered within this class before used.
+ */
+public class WXComponentRegistry {
+
+  private static Map<String, IFComponentHolder> sTypeComponentMap = new ConcurrentHashMap<>();
+  private static ArrayList<Map<String, Object>> sComponentInfos=new ArrayList<>();
+
+  public static synchronized boolean registerComponent(Map<String, ComponentCache> componentCacheMap) {
+    if (componentCacheMap.isEmpty())
+      return true;
+    final Iterator<Map.Entry<String, ComponentCache>> iterator = componentCacheMap.entrySet().iterator();
+    WXBridgeManager.getInstance().post(new Runnable() {
+      @Override
+      public void run() {
+        ArrayList<Map<String, Object>> coms = new ArrayList<>();
+        while (iterator.hasNext()) {
+          Map.Entry<String, ComponentCache> next = iterator.next();
+          try {
+            ComponentCache value = next.getValue();
+            Map<String, Object> registerInfo = value.componentInfo;
+            if (registerInfo == null) {
+              registerInfo = new HashMap<>();
+            }
+            registerInfo.put("type", value.type);
+            registerInfo.put("methods", value.holder.getMethods());
+            registerNativeComponent(value.type, value.holder);
+            sComponentInfos.add(registerInfo);
+            coms.add(registerInfo);
+          } catch (WXException e) {
+            e.printStackTrace();
+          }
+        }
+        WXSDKManager.getInstance().registerComponents(coms);
+      }
+    });
+    return true;
+  }
+
+  public static synchronized boolean registerComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) throws WXException {
+    if (holder == null || TextUtils.isEmpty(type)) {
+      return false;
+    }
+
+    if(RegisterCache.getInstance().cacheComponent(type,holder,componentInfo)) {
+      return true;
+    }
+
+    //execute task in js thread to make sure register order is same as the order invoke register method.
+    WXBridgeManager.getInstance()
+        .post(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          Map<String, Object> registerInfo = componentInfo;
+          if (registerInfo == null){
+            registerInfo = new HashMap<>();
+          }
+
+          registerInfo.put("type",type);
+          registerInfo.put("methods",holder.getMethods());
+          registerNativeComponent(type, holder);
+          registerJSComponent(registerInfo);
+          sComponentInfos.add(registerInfo);
+        } catch (WXException e) {
+          WXLogUtils.e("register component error:", e);
+        }
+
+      }
+    });
+    return true;
+  }
+
+  private static boolean registerNativeComponent(String type, IFComponentHolder holder) throws WXException {
+    try {
+      holder.loadIfNonLazy();
+      sTypeComponentMap.put(type, holder);
+    }catch (ArrayStoreException e){
+      e.printStackTrace();
+      //ignore: ArrayStoreException: java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
+    }
+    return true;
+  }
+
+  private static boolean registerJSComponent(Map<String, Object> componentInfo) throws WXException {
+    ArrayList<Map<String, Object>> coms = new ArrayList<>();
+    coms.add(componentInfo);
+    WXSDKManager.getInstance().registerComponents(coms);
+    return true;
+  }
+
+  public static IFComponentHolder getComponent(String type) {
+    return sTypeComponentMap.get(type);
+  }
+
+  public static void reload(){
+    WXBridgeManager.getInstance().post(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          for(Map<String,Object> com:sComponentInfos){
+            registerJSComponent(com);
+          }
+        } catch (WXException e) {
+          WXLogUtils.e("", e);
+        }
+      }
+    });
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/WXRenderHandler.java b/android/sdk/src/main/java/org/apache/weex/ui/WXRenderHandler.java
new file mode 100644
index 0000000..58c7b7e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/WXRenderHandler.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+class WXRenderHandler extends Handler {
+
+    public WXRenderHandler() {
+        super(Looper.getMainLooper());
+    }
+
+    public final boolean post(String instanceId, Runnable r) {
+        Message msg = Message.obtain(this, r);
+        // Use what to match runnable. Make sure don't override callback method.
+        msg.what = instanceId.hashCode();
+        return sendMessageDelayed(msg, 0);
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        super.handleMessage(msg);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/WXRenderManager.java b/android/sdk/src/main/java/org/apache/weex/ui/WXRenderManager.java
new file mode 100644
index 0000000..d401643
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/WXRenderManager.java
@@ -0,0 +1,311 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui;
+
+import android.opengl.GLES10;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.dom.RenderContext;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.ui.action.BasicGraphicAction;
+import org.apache.weex.ui.action.GraphicActionBatchAction;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+
+/**
+ * Manager class for render operation, mainly for managing {@link RenderContextImpl}.
+ * This is <strong>not</strong> a thread-safe class
+ */
+public class WXRenderManager {
+
+  private volatile ConcurrentHashMap<String, RenderContextImpl> mRenderContext;
+  private WXRenderHandler mWXRenderHandler;
+  private String mCurrentBatchInstanceId = null;
+  private ArrayList<Map<String,Object>> mBatchActions = new ArrayList<>();
+  private final int MAX_DROP_FRAME_NATIVE_BATCH = 2000;
+  private final static  String sKeyAction = "Action";
+  private static int nativeBatchTimes = 0;
+  private static int mOpenGLRenderLimitValue = 0;
+
+  public WXRenderManager() {
+    mRenderContext = new ConcurrentHashMap<>();
+    mWXRenderHandler = new WXRenderHandler();
+  }
+
+  public RenderContext getRenderContext(String instanceId) {
+    return mRenderContext.get(instanceId);
+  }
+
+  public @Nullable
+  WXComponent getWXComponent(String instanceId, String ref) {
+    if (instanceId == null || TextUtils.isEmpty(ref)) {
+      return null;
+    }
+    RenderContext stmt = getRenderContext(instanceId);
+    return stmt == null ? null : stmt.getComponent(ref);
+  }
+
+  public WXSDKInstance getWXSDKInstance(String instanceId) {
+    RenderContextImpl statement = mRenderContext.get(instanceId);
+    if (statement == null) {
+      return null;
+    }
+    return statement.getWXSDKInstance();
+  }
+
+    public static int getOpenGLRenderLimitValue() {
+      if(mOpenGLRenderLimitValue == 0){
+          int maxsize = 0;
+              try {
+                  EGL10 egl = (EGL10) EGLContext.getEGL();
+                  EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+                  int[] vers = new int[2];
+                  egl.eglInitialize(dpy, vers);
+                  int[] configAttr = {
+                          EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER,
+                          EGL10.EGL_LEVEL, 0,
+                          EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,
+                          EGL10.EGL_NONE};
+                  EGLConfig[] configs = new EGLConfig[1];
+                  int[] numConfig = new int[1];
+                  egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig);
+                  if(numConfig[0] == 0){
+                      //There is something wrong with opengl environment.
+                      maxsize = -1;
+                      egl.eglTerminate(dpy);
+                  }else {
+                      EGLConfig config = configs[0];
+                      int[] surfAttr = {
+                              EGL10.EGL_WIDTH, 64,
+                              EGL10.EGL_HEIGHT, 64,
+                              EGL10.EGL_NONE};
+                      EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr);
+                      final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;// missing in EGL10
+                      int[] ctxAttrib = {
+                              EGL_CONTEXT_CLIENT_VERSION, 1,
+                              EGL10.EGL_NONE};
+                      EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib);
+                      egl.eglMakeCurrent(dpy, surf, surf, ctx);
+                      int[] maxSize = new int[1];
+                      GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
+                      egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,
+                              EGL10.EGL_NO_CONTEXT);
+                      egl.eglDestroySurface(dpy, surf);
+                      egl.eglDestroyContext(dpy, ctx);
+                      egl.eglTerminate(dpy);
+                      maxsize = maxSize[0];
+                  }
+              } catch(Exception e){
+                  WXLogUtils.e(WXLogUtils.getStackTrace(e));
+              }
+          mOpenGLRenderLimitValue = maxsize;
+      }
+      return mOpenGLRenderLimitValue;
+    }
+
+  @RestrictTo(Scope.LIBRARY)
+  public void postOnUiThread(Runnable runnable, long delayMillis) {
+    mWXRenderHandler.postDelayed(WXThread.secure(runnable), delayMillis);
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  public void postOnUiThread(Runnable runnable,final String instanceId){
+    mWXRenderHandler.post(instanceId, WXThread.secure(runnable));
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  public void postOnUiThread(Runnable runnable){
+    mWXRenderHandler.post(WXThread.secure(runnable));
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  public void removeTask(Runnable runnable){
+    mWXRenderHandler.removeCallbacks(runnable);
+  }
+
+  /**
+   * Remove renderStatement, can only be invoked in UI thread.
+   *
+   * @param instanceId {@link WXSDKInstance#mInstanceId}
+   */
+  public void removeRenderStatement(String instanceId) {
+    if (!WXUtils.isUiThread()) {
+      throw new WXRuntimeException("[WXRenderManager] removeRenderStatement can only be called in main thread");
+    }
+    RenderContextImpl statement = mRenderContext.remove(instanceId);
+
+    if (statement != null) {
+      statement.destroy();
+    }
+    if(instanceId == null) {
+      mWXRenderHandler.removeCallbacksAndMessages(null);
+    } else {
+      // use hashCode to match message's what.
+      mWXRenderHandler.removeMessages(instanceId.hashCode());
+    }
+  }
+
+  private void postAllStashedGraphicAction(final String instanceId,final BasicGraphicAction action) {
+      final RenderContextImpl renderContext = mRenderContext.get(instanceId);
+
+      /// keep actions if renderContext still exist
+      ArrayList<Map<String, Object>> tmpList = null;
+      if (renderContext != null) {
+        tmpList = new ArrayList<>(mBatchActions);
+      }
+
+      // clear stashed actions
+      this.mBatchActions.clear();
+      mCurrentBatchInstanceId = null;
+      nativeBatchTimes = 0;
+
+      // return if renderContext has been destroyed
+      if (renderContext == null) {
+        return;
+      }
+
+      /// post actions if renderContext still exist
+      ArrayList<BasicGraphicAction> actions = new ArrayList<>(tmpList.size());
+      for (int i = 0 ; i < tmpList.size(); i ++) {
+          Map<String, Object> item = tmpList.get(i);
+          Object mustBeAction = item.get(sKeyAction);
+          if (!(mustBeAction instanceof BasicGraphicAction)) {
+            continue;
+          }
+          BasicGraphicAction tmpAction = (BasicGraphicAction)mustBeAction;
+          if (tmpAction.mActionType == BasicGraphicAction.ActionTypeBatchBegin || tmpAction.mActionType == BasicGraphicAction.ActionTypeBatchEnd) {
+            continue;
+          }
+          actions.add(tmpAction);
+      }
+      postGraphicAction(instanceId, new GraphicActionBatchAction(action.getWXSDKIntance(),action.getRef(), actions));
+  }
+
+  public void postGraphicAction(final String instanceId, final BasicGraphicAction action) {
+    final RenderContextImpl renderContext = mRenderContext.get(instanceId);
+    if (renderContext == null) {
+      return;
+    }
+
+    // If more than two pages exist and mCurrentBatchInstanceId not matches new instanceId, we will post all stashed actions at once.
+    // That will cause losing efficacy of batch action, but it is acceptable because it's not serious problem.
+    if (mCurrentBatchInstanceId != null && instanceId != null && !mCurrentBatchInstanceId.equals(instanceId) && mBatchActions.size() > 0) {
+      Map<String, Object> lastItem = mBatchActions.get(mBatchActions.size() - 1);
+      Object mustBeAction = lastItem.get(sKeyAction);
+      if (mustBeAction instanceof BasicGraphicAction) {
+        BasicGraphicAction lastAction = (BasicGraphicAction)mustBeAction;
+        postAllStashedGraphicAction(mCurrentBatchInstanceId, lastAction);
+      }
+    }
+
+    if (action.mActionType == BasicGraphicAction.ActionTypeBatchEnd) {
+        postAllStashedGraphicAction(instanceId,action);
+        return;
+    } else if (action.mActionType == BasicGraphicAction.ActionTypeBatchBegin || this.mBatchActions.size() > 0 ) {
+        nativeBatchTimes ++ ;
+        if (nativeBatchTimes > MAX_DROP_FRAME_NATIVE_BATCH) {
+            postAllStashedGraphicAction(instanceId,action);
+        } else {
+            HashMap<String, Object> item = new HashMap<>(1);
+            item.put(sKeyAction, action);
+            mBatchActions.add(item);
+            mCurrentBatchInstanceId = instanceId;
+            return;
+        }
+    }
+
+    mWXRenderHandler.post(instanceId, action);
+  }
+
+  public void registerInstance(WXSDKInstance instance) {
+    if (instance.getInstanceId() == null) {
+      WXExceptionUtils.commitCriticalExceptionRT(null,
+              WXErrorCode.WX_RENDER_ERR_INSTANCE_ID_NULL,
+              "registerInstance",
+              WXErrorCode.WX_RENDER_ERR_INSTANCE_ID_NULL.getErrorMsg() + "instanceId is null",
+              null);
+    } else {
+      mRenderContext.put(instance.getInstanceId(), new RenderContextImpl(instance));
+    }
+  }
+
+  public List<WXSDKInstance> getAllInstances() {
+    ArrayList<WXSDKInstance> instances = null;
+    if (mRenderContext != null && !mRenderContext.isEmpty()) {
+      instances = new ArrayList<WXSDKInstance>();
+      for (Map.Entry<String, RenderContextImpl> entry : mRenderContext.entrySet()) {
+        RenderContextImpl renderStatement = entry.getValue();
+        if (renderStatement != null) {
+          instances.add(renderStatement.getWXSDKInstance());
+        }
+      }
+    }
+    return instances;
+  }
+
+  public void registerComponent(String instanceId, String ref, WXComponent comp) {
+    RenderContextImpl statement = mRenderContext.get(instanceId);
+    if (statement != null) {
+      statement.registerComponent(ref, comp);
+      if (null != statement.getInstance()){
+        statement.getInstance().getApmForInstance().updateMaxStats(
+            WXInstanceApm.KEY_PAGE_STATS_MAX_COMPONENT_NUM,
+            statement.getComponentCount()
+        );
+      }
+    }
+  }
+
+  public WXComponent unregisterComponent(String instanceId, String ref) {
+    RenderContextImpl statement = mRenderContext.get(instanceId);
+    if (statement != null) {
+      if (null != statement.getInstance()){
+        statement.getInstance().getApmForInstance().updateMaxStats(
+            WXInstanceApm.KEY_PAGE_STATS_MAX_COMPONENT_NUM,
+            statement.getComponentCount()
+        );
+      }
+      return statement.unregisterComponent(ref);
+    } else {
+      return null;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/ActionAddRule.java b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionAddRule.java
new file mode 100644
index 0000000..70d3933
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionAddRule.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.font.FontAdapter;
+import org.apache.weex.utils.FontDO;
+import org.apache.weex.utils.TypefaceUtil;
+
+/**
+ * Created by listen on 18/01/10.
+ */
+public class ActionAddRule implements IExecutable {
+
+  private final String mPageId;
+  private final String mType;
+  private final JSONObject mData;
+
+  public ActionAddRule(String pageId, String type, JSONObject data) {
+    this.mPageId = pageId;
+    this.mType = type;
+    this.mData = data;
+  }
+
+  @Override
+  public void executeAction() {
+    WXSDKInstance instance = WXSDKManager.getInstance().getWXRenderManager().getWXSDKInstance(mPageId);
+    if (instance == null || instance.isDestroy()) {
+      return;
+    }
+
+    if (!Constants.Name.FONT_FACE.equals(mType)) {
+      return;
+    }
+
+    FontDO fontDO = parseFontDO(mData, instance);
+    if (fontDO != null && !TextUtils.isEmpty(fontDO.getFontFamilyName())) {
+      notifyAddFontRule(instance, fontDO);
+      FontDO cacheFontDO = TypefaceUtil.getFontDO(fontDO.getFontFamilyName());
+      if (cacheFontDO == null || !TextUtils.equals(cacheFontDO.getUrl(), fontDO.getUrl())) {
+        TypefaceUtil.putFontDO(fontDO);
+        TypefaceUtil.loadTypeface(fontDO, true);
+      } else {
+        TypefaceUtil.loadTypeface(cacheFontDO, true);
+      }
+    }
+
+  }
+
+  private FontDO parseFontDO(JSONObject jsonObject,WXSDKInstance instance) {
+    if(jsonObject == null) {
+      return null;
+    }
+    String src = jsonObject.getString(Constants.Name.SRC);
+    String name = jsonObject.getString(Constants.Name.FONT_FAMILY);
+
+    return new FontDO(name, src,instance);
+  }
+
+
+  private void notifyAddFontRule(WXSDKInstance instance, FontDO fontDO){
+    FontAdapter fontAdapter = WXSDKManager.getInstance().getFontAdapter();
+    if(fontAdapter != null){
+        fontAdapter.onAddFontRule(instance.getInstanceId(), fontDO.getFontFamilyName(), fontDO.getUrl());
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/ActionGetComponentRect.java b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionGetComponentRect.java
new file mode 100644
index 0000000..9f2e96d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionGetComponentRect.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.view.View;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.bridge.SimpleJSCallback;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by listen on 18/01/10.
+ */
+public class ActionGetComponentRect extends BasicGraphicAction {
+
+  private final String mCallback;
+
+  public ActionGetComponentRect(WXSDKInstance instance, String ref, String callback) {
+    super(instance, ref);
+    this.mCallback = callback;
+  }
+
+  @Override
+  public void executeAction() {
+    WXSDKInstance instance = getWXSDKIntance();
+    if (instance == null || instance.isDestroy()) {
+      return;
+    }
+
+    JSCallback jsCallback = new SimpleJSCallback(instance.getInstanceId(), mCallback);
+
+    if (TextUtils.isEmpty(getRef())) {
+      Map<String, Object> options = new HashMap<>();
+      options.put("result", false);
+      options.put("errMsg", "Illegal parameter");
+      jsCallback.invoke(options);
+    } else if ("viewport".equalsIgnoreCase(getRef())) {
+      callbackViewport(instance, jsCallback);
+    } else {
+      WXComponent component = WXSDKManager
+          .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+      if (component == null) {
+        return;
+      }
+
+      Map<String, Object> options = new HashMap<>();
+      if (component != null) {
+        int viewPort = instance.getInstanceViewPortWidth();
+        Map<String, Float> size = new HashMap<>();
+        Rect sizes = component.getComponentSize();
+        size.put("width", getWebPxValue(sizes.width(),viewPort));
+        size.put("height", getWebPxValue(sizes.height(),viewPort));
+        size.put("bottom", getWebPxValue(sizes.bottom,viewPort));
+        size.put("left", getWebPxValue(sizes.left,viewPort));
+        size.put("right", getWebPxValue(sizes.right,viewPort));
+        size.put("top", getWebPxValue(sizes.top,viewPort));
+        options.put("size", size);
+        options.put("result", true);
+      } else {
+        options.put("errMsg", "Component does not exist");
+      }
+      jsCallback.invoke(options);
+    }
+  }
+
+  private void callbackViewport(WXSDKInstance instance, JSCallback jsCallback) {
+    View container;
+    if ((container = instance.getContainerView()) != null) {
+      Map<String, Object> options = new HashMap<>();
+      Map<String, Float> sizes = new HashMap<>();
+      int[] location = new int[2];
+      instance.getContainerView().getLocationOnScreen(location);
+      int viewport = instance.getInstanceViewPortWidth();
+      sizes.put("left", 0f);
+      sizes.put("top", 0f);
+      sizes.put("right", getWebPxValue(container.getWidth(),viewport));
+      sizes.put("bottom", getWebPxValue(container.getHeight(),viewport));
+      sizes.put("width", getWebPxValue(container.getWidth(),viewport));
+      sizes.put("height", getWebPxValue(container.getHeight(),viewport));
+      options.put("size", sizes);
+      options.put("result", true);
+      jsCallback.invoke(options);
+    } else {
+      Map<String, Object> options = new HashMap<>();
+      options.put("result", false);
+      options.put("errMsg", "Component does not exist");
+      jsCallback.invoke(options);
+    }
+  }
+
+  @NonNull
+  private float getWebPxValue(int value,int viewport) {
+    return WXViewUtils.getWebPxByWidth(value, viewport);
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/ActionGetLayoutDirection.java b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionGetLayoutDirection.java
new file mode 100644
index 0000000..64de952
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionGetLayoutDirection.java
@@ -0,0 +1,118 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.view.View;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.bridge.SimpleJSCallback;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by listen on 18/09/12.
+ */
+public class ActionGetLayoutDirection extends BasicGraphicAction {
+
+  private final String mCallback;
+
+  public ActionGetLayoutDirection(WXSDKInstance instance, String ref, String callback) {
+    super(instance, ref);
+    this.mCallback = callback;
+  }
+
+  @Override
+  public void executeAction() {
+    WXSDKInstance instance = getWXSDKIntance();
+    if (instance == null || instance.isDestroy()) {
+      return;
+    }
+
+    JSCallback jsCallback = new SimpleJSCallback(instance.getInstanceId(), mCallback);
+
+    if (TextUtils.isEmpty(getRef())) {
+      Map<String, Object> options = new HashMap<>();
+      options.put("result", false);
+      options.put("errMsg", "Illegal parameter");
+      jsCallback.invoke(options);
+    } else if ("viewport".equalsIgnoreCase(getRef())) {
+      callbackViewport(instance, jsCallback);
+    } else {
+      WXComponent component = WXSDKManager
+          .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+      if (component == null) {
+        return;
+      }
+
+      String directionRet = "ltr";
+      if (component != null) {
+        int direction = NativeRenderObjectUtils.nativeRenderObjectGetLayoutDirectionFromPathNode(component.getRenderObjectPtr());
+        switch (direction) {
+          case 0: {
+            directionRet = "inherit";
+            break;
+          }
+          case 1: {
+            directionRet = "ltr";
+            break;
+          }
+          case 2: {
+            directionRet = "rtl";
+            break;
+          }
+          default: {
+            directionRet = "ltr";
+            break;
+          }
+
+        }
+      }
+      jsCallback.invoke(directionRet);
+    }
+  }
+
+  private void callbackViewport(WXSDKInstance instance, JSCallback jsCallback) {
+    View container;
+    if ((container = instance.getContainerView()) != null) {
+      Map<String, Object> options = new HashMap<>();
+      options.put("direction", "ltr");
+      options.put("result", true);
+      jsCallback.invoke(options);
+    } else {
+      Map<String, Object> options = new HashMap<>();
+      options.put("result", false);
+      options.put("errMsg", "Component does not exist");
+      jsCallback.invoke(options);
+    }
+  }
+
+  @NonNull
+  private float getWebPxValue(int value,int viewport) {
+    return WXViewUtils.getWebPxByWidth(value, viewport);
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/ActionInvokeMethod.java b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionInvokeMethod.java
new file mode 100644
index 0000000..0d5bf2a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionInvokeMethod.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import com.alibaba.fastjson.JSONArray;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXLogUtils;
+
+/**
+ * Created by listen on 18/01/10.
+ */
+public class ActionInvokeMethod implements IExecutable {
+
+  private static final String TAG = "ActionInvokeMethod";
+
+  private final String mMethod;
+  private final JSONArray mArgs;
+  private String mPageId;
+  private String mRef;
+
+  public ActionInvokeMethod(String pageId, String ref, String method, JSONArray args) {
+    this.mPageId = pageId;
+    this.mRef = ref;
+    this.mMethod = method;
+    this.mArgs = args;
+  }
+
+  @Override
+  public void executeAction() {
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(mPageId, mRef);
+    if(component == null){
+      WXLogUtils.e(TAG,"target component not found.");
+      return;
+    }
+    component.invoke(mMethod,mArgs);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/ActionReloadPage.java b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionReloadPage.java
new file mode 100644
index 0000000..96830c3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/ActionReloadPage.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.util.Log;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+
+/**
+ * Created by listen on 18/01/09.
+ */
+public class ActionReloadPage implements IExecutable {
+
+  private final String TAG = "ReloadPageAction";
+  private boolean mReloadThis;
+  private String mPageId;
+
+  public ActionReloadPage(String pageId, boolean reloadThis) {
+    this.mPageId = pageId;
+    this.mReloadThis = reloadThis;
+  }
+
+  @Override
+  public void executeAction() {
+    final WXSDKInstance instance = WXSDKManager.getInstance().getWXRenderManager().getWXSDKInstance(mPageId);
+    if (instance != null) {
+      instance.reloadPage(mReloadThis);
+    } else {
+      Log.e(TAG, "ReloadPageAction executeDom reloadPage instance is null");
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/BasicComponentData.java b/android/sdk/src/main/java/org/apache/weex/ui/action/BasicComponentData.java
new file mode 100644
index 0000000..c91969c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/BasicComponentData.java
@@ -0,0 +1,310 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+import android.view.View;
+
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.Map;
+import java.util.Set;
+
+public class BasicComponentData<T extends View> {
+
+  public String mRef;
+  public String mComponentType;
+  public String mParentRef;
+  private WXStyle mStyles;
+  private WXAttr mAttributes;
+  private WXEvent mEvents;
+  private CSSShorthand mMargins;
+  private CSSShorthand mPaddings;
+  private CSSShorthand mBorders;
+  private long renderObjectPr = 0;
+
+  public BasicComponentData(String ref, String componentType, String parentRef) {
+    this.mRef = ref;
+    this.mComponentType = componentType;
+    this.mParentRef = parentRef;
+  }
+
+  public void addStyle(Map<String, Object> styles) {
+    addStyle(styles, false);
+  }
+
+  public final void addStyle(Map<String, Object> styles, boolean byPesudo) {
+    if (styles == null || styles.isEmpty()) {
+      return;
+    }
+    if (mStyles == null) {
+      mStyles = new WXStyle(styles);
+    }
+    else {
+      mStyles.putAll(styles, byPesudo);
+    }
+  }
+
+  public final void addAttr(Map<String, Object> attrs) {
+    if (attrs == null || attrs.isEmpty()) {
+      return;
+    }
+    if (mAttributes == null) {
+      mAttributes = new WXAttr(attrs, 0);
+    }
+    else {
+      mAttributes.putAll(attrs);
+    }
+  }
+
+  public final void addEvent(Set<String> events) {
+    if (events == null || events.isEmpty()) {
+      return;
+    }
+    if (mEvents == null) {
+      mEvents = new WXEvent();
+    }
+    mEvents.addAll(events);
+  }
+
+  public final void addShorthand(float[] shorthand, CSSShorthand.TYPE type) {
+    if (shorthand == null) {
+      shorthand = new float[] {0, 0, 0, 0};
+    }
+    if (shorthand.length == 4) {
+      switch (type) {
+        case MARGIN:
+          if (mMargins == null) {
+            mMargins = new CSSShorthand(shorthand);
+          } else {
+            mMargins.replace(shorthand);
+          }
+          break;
+        case PADDING:
+          if (mPaddings == null) {
+            mPaddings = new CSSShorthand(shorthand);
+          } else {
+            mPaddings.replace(shorthand);
+          }
+          break;
+        case BORDER:
+          if (mBorders == null) {
+            mBorders = new CSSShorthand(shorthand);
+          } else {
+            mBorders.replace(shorthand);
+          }
+          break;
+        default:
+          break;
+      }
+    }
+  }
+
+  public final void addShorthand(Map<String, String> shorthand) {
+    if (shorthand != null && !shorthand.isEmpty()) {
+      for (Map.Entry<String, String> item : shorthand.entrySet()) {
+        String key = item.getKey();
+        switch (key) {
+          case Constants.Name.MARGIN:
+            addMargin(CSSShorthand.EDGE.ALL, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.MARGIN_LEFT:
+            addMargin(CSSShorthand.EDGE.LEFT, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.MARGIN_TOP:
+            addMargin(CSSShorthand.EDGE.TOP, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.MARGIN_RIGHT:
+            addMargin(CSSShorthand.EDGE.RIGHT, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.MARGIN_BOTTOM:
+            addMargin(CSSShorthand.EDGE.BOTTOM,WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.BORDER_WIDTH:
+            addBorder(CSSShorthand.EDGE.ALL, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.BORDER_TOP_WIDTH:
+            addBorder(CSSShorthand.EDGE.TOP, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.BORDER_RIGHT_WIDTH:
+            addBorder(CSSShorthand.EDGE.RIGHT, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.BORDER_BOTTOM_WIDTH:
+            addBorder(CSSShorthand.EDGE.BOTTOM, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.BORDER_LEFT_WIDTH:
+            addBorder(CSSShorthand.EDGE.LEFT, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.PADDING:
+            addPadding(CSSShorthand.EDGE.ALL, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.PADDING_LEFT:
+            addPadding(CSSShorthand.EDGE.LEFT, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.PADDING_TOP:
+            addPadding(CSSShorthand.EDGE.TOP, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.PADDING_RIGHT:
+            addPadding(CSSShorthand.EDGE.RIGHT, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+          case Constants.Name.PADDING_BOTTOM:
+            addPadding(CSSShorthand.EDGE.BOTTOM, WXUtils.fastGetFloat(shorthand.get(key)));
+            break;
+        }
+      }
+    }
+  }
+
+  private void addMargin(CSSShorthand.EDGE spacingType, float margin) {
+    if (mMargins == null) {
+      mMargins = new CSSShorthand();
+    }
+    mMargins.set(spacingType, margin);
+  }
+
+  private void addPadding(CSSShorthand.EDGE spacingType, float padding) {
+    if (mPaddings == null) {
+      mPaddings = new CSSShorthand();
+    }
+    mPaddings.set(spacingType, padding);
+  }
+
+  private void addBorder(CSSShorthand.EDGE spacingType, float border) {
+    if (mBorders == null) {
+      mBorders = new CSSShorthand();
+    }
+    mBorders.set(spacingType, border);
+  }
+
+  public final @NonNull
+  WXStyle getStyles() {
+    if (mStyles == null) {
+      mStyles = new WXStyle();
+    }
+    return mStyles;
+  }
+
+  public final @NonNull
+  WXAttr getAttrs() {
+    if (mAttributes == null) {
+      mAttributes = new WXAttr();
+    }
+    return mAttributes;
+  }
+
+  public final @NonNull
+  WXEvent getEvents() {
+    if (mEvents == null) {
+      mEvents = new WXEvent();
+    }
+    return mEvents;
+  }
+
+  /**
+   * Get this node's margin, as defined by cssstyle + default margin.
+   */
+  public final @NonNull
+  CSSShorthand getMargin() {
+    if (mMargins == null) {
+      mMargins = new CSSShorthand();
+    }
+    return mMargins;
+  }
+
+  /**
+   * Get this node's padding, as defined by cssstyle + default padding.
+   */
+  public final @NonNull
+  CSSShorthand getPadding() {
+    if (mPaddings == null) {
+      mPaddings = new CSSShorthand();
+    }
+    return mPaddings;
+  }
+
+  /**
+   * Get this node's border, as defined by cssstyle.
+   */
+  public @NonNull
+  CSSShorthand getBorder() {
+    if (mBorders == null) {
+      mBorders = new CSSShorthand();
+    }
+    return mBorders;
+  }
+
+  public final void setMargins(@NonNull CSSShorthand mMargins) {
+    this.mMargins = mMargins;
+  }
+
+  public final void setPaddings(@NonNull CSSShorthand mPaddings) {
+    this.mPaddings = mPaddings;
+  }
+
+  public final void setBorders(@NonNull CSSShorthand mBorders) {
+    this.mBorders = mBorders;
+  }
+
+
+
+  @Override
+  public BasicComponentData clone() throws CloneNotSupportedException {
+    BasicComponentData basicComponentData = new BasicComponentData(mRef, mComponentType, mParentRef);
+    basicComponentData.setBorders(getBorder().clone());
+    basicComponentData.setMargins(getMargin().clone());
+    basicComponentData.setPaddings(getPadding().clone());
+    if(mAttributes != null){
+      basicComponentData.mAttributes = mAttributes.clone();
+    }
+    if(mStyles != null){
+      basicComponentData.mStyles = mStyles.clone();
+    }
+    if(mEvents != null){
+      basicComponentData.mEvents = mEvents.clone();
+    }
+
+    if(renderObjectPr != 0){
+      basicComponentData.setRenderObjectPr(NativeRenderObjectUtils.nativeCopyRenderObject(renderObjectPr));
+    }
+    return basicComponentData;
+  }
+
+  public long getRenderObjectPr() {
+    return renderObjectPr;
+  }
+
+  public boolean isRenderPtrEmpty(){
+    return  renderObjectPr == 0;
+  }
+
+  public synchronized void setRenderObjectPr(long renderObjectPr) {
+    if(this.renderObjectPr != renderObjectPr){
+      if(this.renderObjectPr != 0){
+        throw  new  RuntimeException("RenderObjectPr has " + renderObjectPr + " old renderObjectPtr " + this.renderObjectPr);
+      }
+      this.renderObjectPr = renderObjectPr;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/BasicGraphicAction.java b/android/sdk/src/main/java/org/apache/weex/ui/action/BasicGraphicAction.java
new file mode 100644
index 0000000..16e5472
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/BasicGraphicAction.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.text.TextUtils;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.utils.WXLogUtils;
+
+public abstract class BasicGraphicAction implements IExecutable, Runnable {
+
+  private WXSDKInstance mInstance;
+  private final String mRef;
+  public int mActionType = ActionTypeNormal;
+  public static final int ActionTypeBatchBegin = 1;
+  public static final int ActionTypeBatchEnd = 2;
+  public static final int ActionTypeNormal = 0;
+
+
+  public BasicGraphicAction(WXSDKInstance instance, String ref) {
+    this.mInstance = instance;
+    this.mRef = ref;
+  }
+
+  public final WXSDKInstance getWXSDKIntance() {
+    return mInstance;
+  }
+
+  public final String getPageId() {
+    return mInstance.getInstanceId();
+  }
+
+  public final String getRef() {
+    return mRef;
+  }
+
+  public void executeActionOnRender() {
+    if (TextUtils.isEmpty(mInstance.getInstanceId())) {
+        WXLogUtils.e("[BasicGraphicAction] pageId can not be null");
+        if (WXEnvironment.isApkDebugable()) {
+            throw new RuntimeException("["+getClass().getName()+"] pageId can not be null");
+        }
+        return;
+    }
+    WXSDKManager
+        .getInstance().getWXRenderManager().postGraphicAction(mInstance.getInstanceId(), this);
+  }
+
+  @Override
+  public void run() {
+    try {
+      executeAction();
+    } catch (Throwable e) {
+      //catch everything may throw from exection.
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e("BasicGraphicAction",
+            "SafeRunnable run throw expection:" + e.getMessage());
+        throw e;
+      }
+      WXLogUtils.w("BasicGraphicAction", e);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAbstractAddElement.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAbstractAddElement.java
new file mode 100644
index 0000000..13e429e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAbstractAddElement.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.v4.util.ArrayMap;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXComponentFactory;
+import org.apache.weex.ui.component.WXVContainer;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class GraphicActionAbstractAddElement extends BasicGraphicAction {
+
+  protected String mComponentType;
+  protected String mParentRef;
+  protected int mIndex = -1;
+  protected Map<String, String> mStyle;
+  protected Map<String, String> mAttributes;
+  protected Set<String> mEvents;
+  protected float[] mMargins;
+  protected float[] mPaddings;
+  protected float[] mBorders;
+  private long startTime;
+
+  public GraphicActionAbstractAddElement(WXSDKInstance instance, String ref) {
+    super(instance, ref);
+    startTime = System.currentTimeMillis();
+  }
+
+  protected WXComponent createComponent(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    long createComponentStart = System.currentTimeMillis();
+    if (basicComponentData != null) {
+      basicComponentData.addStyle(mStyle);
+      basicComponentData.addAttr(mAttributes);
+      basicComponentData.addEvent(mEvents);
+      basicComponentData.addShorthand(mMargins, CSSShorthand.TYPE.MARGIN);
+      basicComponentData.addShorthand(mPaddings, CSSShorthand.TYPE.PADDING);
+      basicComponentData.addShorthand(mBorders, CSSShorthand.TYPE.BORDER);
+    }
+
+    WXComponent component = WXComponentFactory.newInstance(instance, parent, basicComponentData);
+    WXSDKManager
+        .getInstance().getWXRenderManager().registerComponent(getPageId(), getRef(), component);
+    if(mStyle != null && mStyle.containsKey(Constants.Name.TRANSFORM) && component.getTransition() == null) {
+      Map<String, Object> animationMap = new ArrayMap<>(2);
+      animationMap.put(Constants.Name.TRANSFORM, mStyle.get(Constants.Name.TRANSFORM));
+      animationMap
+          .put(Constants.Name.TRANSFORM_ORIGIN, mStyle.get(Constants.Name.TRANSFORM_ORIGIN));
+      component.addAnimationForElement(animationMap);
+    }
+    instance.onComponentCreate(component,System.currentTimeMillis() -createComponentStart);
+    return component;
+  }
+
+  @Override
+  public void executeAction() {
+    getWXSDKIntance().callActionAddElementTime(System.currentTimeMillis() - startTime);
+  }
+
+  public String getComponentType() {
+    return mComponentType;
+  }
+
+  public String getParentRef() {
+    return mParentRef;
+  }
+
+  public int getIndex() {
+    return mIndex;
+  }
+
+  public Map<String, String> getStyle() {
+    return mStyle;
+  }
+
+  public Map<String, String> getAttributes() {
+    return mAttributes;
+  }
+
+  public Set<String> getEvents() {
+    return mEvents;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddChildToRichtext.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddChildToRichtext.java
new file mode 100755
index 0000000..e2e7ca7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddChildToRichtext.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.richtext.WXRichText;
+
+import java.util.HashMap;
+
+public class GraphicActionAddChildToRichtext extends BasicGraphicAction {
+
+    public GraphicActionAddChildToRichtext(@NonNull WXSDKInstance instance, String nodeType, String ref, String parentRef, String richTextRef,
+                                           HashMap<String, String> styles, HashMap<String, String> attrs){
+        super(instance,richTextRef);
+        if(WXSDKManager.getInstance() != null && WXSDKManager.getInstance().getWXRenderManager() != null) {
+            WXRichText richText = (WXRichText) WXSDKManager.getInstance().getWXRenderManager()
+                    .getWXComponent(getPageId(), richTextRef);
+            if (richText != null) {
+                richText.AddChildNode(ref, nodeType, parentRef, styles, attrs);
+            }
+        }
+    }
+    @Override
+    public void executeAction() {
+
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddElement.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddElement.java
new file mode 100644
index 0000000..8ab6cba
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddElement.java
@@ -0,0 +1,214 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.annotation.WorkerThread;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Log;
+import org.apache.weex.BuildConfig;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.dom.transition.WXTransition;
+import org.apache.weex.performance.WXAnalyzerDataTransfer;
+import org.apache.weex.performance.WXStateRecord;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+public class GraphicActionAddElement extends GraphicActionAbstractAddElement {
+
+  private WXVContainer parent;
+  private WXComponent child;
+  private GraphicPosition layoutPosition;
+  private GraphicSize layoutSize;
+  private boolean isLayoutRTL;
+
+  public GraphicActionAddElement(@NonNull WXSDKInstance instance, String ref,
+                                 String componentType, String parentRef,
+                                 int index,
+                                 Map<String, String> style,
+                                 Map<String, String> attributes,
+                                 Set<String> events,
+                                 float[] margins,
+                                 float[] paddings,
+                                 float[] borders) {
+    super(instance, ref);
+    this.mComponentType = componentType;
+    this.mParentRef = parentRef;
+    this.mIndex = index;
+    this.mStyle = style;
+    this.mAttributes = attributes;
+    this.mEvents = events;
+    this.mPaddings = paddings;
+    this.mMargins = margins;
+    this.mBorders = borders;
+
+    if (instance.getContext() == null) {
+      return;
+    }
+      if (WXAnalyzerDataTransfer.isInteractionLogOpen()){
+        Log.d(WXAnalyzerDataTransfer.INTERACTION_TAG, "[client][addelementStart]"+instance.getInstanceId()+","+componentType+","+ref);
+      }
+    try {
+      parent = (WXVContainer) WXSDKManager.getInstance().getWXRenderManager()
+          .getWXComponent(getPageId(), mParentRef);
+      long start = WXUtils.getFixUnixTime();
+      BasicComponentData basicComponentData = new BasicComponentData(ref, mComponentType,
+          mParentRef);
+      child = createComponent(instance, parent, basicComponentData);
+      child.setTransition(WXTransition.fromMap(child.getStyles(), child));
+      long diff = WXUtils.getFixUnixTime()-start;
+      instance.getApmForInstance().componentCreateTime += diff;
+      if (null != parent && parent.isIgnoreInteraction){
+        child.isIgnoreInteraction = true;
+      }
+      if (!child.isIgnoreInteraction ){
+        Object flag = null;
+        if (null != child.getAttrs()){
+          flag = child.getAttrs().get("ignoreInteraction");
+        }
+        if ("false".equals(flag) || "0".equals(flag)){
+          child.isIgnoreInteraction = false;
+        }else if ("1".equals(flag) || "true".equals(flag) || child.isFixed()){
+          child.isIgnoreInteraction = true;
+        }
+      }
+      WXStateRecord.getInstance().recordAction(instance.getInstanceId(),"addElement");
+
+    } catch (ClassCastException e) {
+      Map<String, String> ext = new ArrayMap<>();
+      WXComponent parent = WXSDKManager.getInstance().getWXRenderManager()
+          .getWXComponent(getPageId(), mParentRef);
+
+      if (mStyle != null && !mStyle.isEmpty()) {
+        ext.put("child.style", mStyle.toString());
+      }
+      if (parent != null && parent.getStyles() != null && !parent.getStyles().isEmpty()) {
+        ext.put("parent.style", parent.getStyles().toString());
+      }
+
+      if (mAttributes != null && !mAttributes.isEmpty()) {
+        ext.put("child.attr", mAttributes.toString());
+      }
+      if (parent != null && parent.getAttrs() != null && !parent.getAttrs().isEmpty()) {
+        ext.put("parent.attr", parent.getAttrs().toString());
+      }
+
+      if (mEvents != null && !mEvents.isEmpty()) {
+        ext.put("child.event", mEvents.toString());
+      }
+      if (parent != null && parent.getEvents() != null && !parent.getEvents().isEmpty()) {
+        ext.put("parent.event", parent.getEvents().toString());
+      }
+
+      if (mMargins != null && mMargins.length > 0) {
+        ext.put("child.margin", Arrays.toString(mMargins));
+      }
+      if (parent != null && parent.getMargin() != null) {
+        ext.put("parent.margin", parent.getMargin().toString());
+      }
+
+      if (mPaddings != null && mPaddings.length > 0) {
+        ext.put("child.padding", Arrays.toString(mPaddings));
+      }
+      if (parent != null && parent.getPadding() != null) {
+        ext.put("parent.padding", parent.getPadding().toString());
+      }
+
+      if (mBorders != null && mBorders.length > 0) {
+        ext.put("child.border", Arrays.toString(mBorders));
+      }
+      if (parent != null && parent.getBorder() != null) {
+        ext.put("parent.border", parent.getBorder().toString());
+      }
+
+      WXExceptionUtils.commitCriticalExceptionRT(instance.getInstanceId(),
+          WXErrorCode.WX_RENDER_ERR_CONTAINER_TYPE,
+          "GraphicActionAddElement",
+          String.format(Locale.ENGLISH,"You are trying to add a %s to a %2$s, which is illegal as %2$s is not a container",
+              componentType,
+              WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), mParentRef).getComponentType()),
+          ext);
+    }
+
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  @WorkerThread
+  public void setRTL(boolean isRTL){
+    this.isLayoutRTL = isRTL;
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  @WorkerThread
+  public void setSize(GraphicSize graphicSize){
+    this.layoutSize = graphicSize;
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  @WorkerThread
+  public void setPosition(GraphicPosition position){
+    this.layoutPosition = position;
+  }
+
+  @RestrictTo(Scope.LIBRARY)
+  @WorkerThread
+  public void setIndex(int index){
+    mIndex = index;
+  }
+
+  @Override
+  public void executeAction() {
+    super.executeAction();
+    try {
+      if (!TextUtils.equals(mComponentType, "video") && !TextUtils.equals(mComponentType, "videoplus"))
+        child.mIsAddElementToTree = true;
+
+      long start = WXUtils.getFixUnixTime();
+      parent.addChild(child, mIndex);
+      parent.createChildViewAt(mIndex);
+
+      child.setIsLayoutRTL(isLayoutRTL);
+      if(layoutPosition !=null && layoutSize != null) {
+        child.setDemission(layoutSize, layoutPosition);
+      }
+      child.applyLayoutAndEvent(child);
+      child.bindData(child);
+      long diff = WXUtils.getFixUnixTime() - start;
+      if (null != getWXSDKIntance()){
+        getWXSDKIntance().getApmForInstance().viewCreateTime +=diff;
+      }
+
+    } catch (Exception e) {
+      WXLogUtils.e("add component failed.", e);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddEvent.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddEvent.java
new file mode 100644
index 0000000..0134ead
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAddEvent.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.tracing.Stopwatch;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by listen on 18/01/11.
+ */
+public class GraphicActionAddEvent extends BasicGraphicAction {
+
+  private final String mEvent;
+
+  public GraphicActionAddEvent(WXSDKInstance instance, String ref, Object event) {
+    super(instance, ref);
+    this.mEvent = WXEvent.getEventName(event);
+  }
+
+  @Override
+  public void executeAction() {
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      return;
+    }
+
+    Stopwatch.tick();
+    if (!component.getEvents().contains(mEvent)) {
+      component.getEvents().addEvent(mEvent);
+    }
+    component.addEvent(mEvent);
+    Stopwatch.split("addEventToComponent");
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAnimation.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAnimation.java
new file mode 100644
index 0000000..f7831be
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAnimation.java
@@ -0,0 +1,290 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.view.animation.PathInterpolatorCompat;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.animation.BackgroundColorProperty;
+import org.apache.weex.ui.animation.HeightProperty;
+import org.apache.weex.ui.animation.WXAnimationBean;
+import org.apache.weex.ui.animation.WXAnimationModule;
+import org.apache.weex.ui.animation.WidthProperty;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.list.template.TemplateDom;
+import org.apache.weex.ui.view.border.BorderDrawable;
+import org.apache.weex.utils.SingleFunctionParser;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.HashMap;
+import java.util.List;
+
+public class GraphicActionAnimation extends BasicGraphicAction {
+
+  private final static String TAG = "GraphicActionAnimation";
+
+  private final boolean styleNeedInit;
+
+  @Nullable
+  private
+  final String callback;
+
+  @Nullable
+  private
+  WXAnimationBean mAnimationBean;
+
+  public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref, @NonNull WXAnimationBean animationBean) {
+    super(instance, ref);
+    this.styleNeedInit = false;
+    this.callback = null;
+    this.mAnimationBean = animationBean;
+  }
+
+  public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref, @Nullable String animation,
+                                @Nullable final String callBack) {
+    super(instance, ref);
+    this.styleNeedInit = true;
+    this.callback = callBack;
+    if (!TextUtils.isEmpty(animation)) {
+      this.mAnimationBean = JSONObject.parseObject(animation, WXAnimationBean.class);
+    }
+  }
+  public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref, @NonNull WXAnimationBean animationBean,
+                                @Nullable final String callBack) {
+    super(instance, ref);
+    this.styleNeedInit = false;
+    this.mAnimationBean = animationBean;
+    this.callback = callBack;
+  }
+
+  @Override
+  public void executeAction() {
+    if (null == mAnimationBean) {
+      return;
+    }
+
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      if(!TemplateDom.isVirtualDomRef(getRef())){
+        return;
+      }
+      component = TemplateDom.findVirtualComponentByVRef(getPageId(), getRef());
+      if(component == null){
+        return;
+      }
+    }
+
+    WXSDKInstance instance = WXSDKManager.getInstance().getWXRenderManager().getWXSDKInstance(getPageId());
+    if (instance == null) {
+      return;
+    }
+
+    if (null != mAnimationBean.styles) {
+      if(styleNeedInit) {
+        // Synchronize transformOrigin between component styles and animation style before
+        // animation start.
+        String transformOrigin = (String) component.getStyles().get(Constants.Name.TRANSFORM_ORIGIN);
+        if (TextUtils.isEmpty(mAnimationBean.styles.transformOrigin)) {
+          mAnimationBean.styles.transformOrigin = transformOrigin;
+        }
+        mAnimationBean.styles.init(mAnimationBean.styles.transformOrigin,
+            mAnimationBean.styles.transform, (int) component.getLayoutWidth(),
+            (int) component.getLayoutHeight(),
+            instance.getInstanceViewPortWidth(), instance);
+      }
+      startAnimation(instance, component);
+    }
+  }
+
+
+
+  private void startAnimation(@NonNull WXSDKInstance instance, @Nullable WXComponent component) {
+    if (component != null) {
+      if (mAnimationBean != null) {
+        component.setNeedLayoutOnAnimation(mAnimationBean.needLayout);
+      }
+      if (component.getHostView() == null) {
+        WXAnimationModule.AnimationHolder holder = new WXAnimationModule.AnimationHolder(mAnimationBean, callback);
+        component.postAnimation(holder);
+      } else {
+        try {
+          Animator animator = createAnimator(component.getHostView(), instance
+              .getInstanceViewPortWidth());
+          if (animator != null) {
+            Animator.AnimatorListener animatorCallback = createAnimatorListener(instance, callback);
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2 && component
+                .isLayerTypeEnabled() ) {
+              component.getHostView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+            Interpolator interpolator = createTimeInterpolator();
+            if (animatorCallback != null) {
+              animator.addListener(animatorCallback);
+            }
+            if (interpolator != null) {
+              animator.setInterpolator(interpolator);
+            }
+            component.getHostView().setCameraDistance(mAnimationBean.styles.getCameraDistance());
+            animator.setDuration(mAnimationBean.duration);
+            animator.start();
+          }
+        } catch (RuntimeException e) {
+          WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
+        }
+      }
+    }
+  }
+
+  private
+  @Nullable
+  ObjectAnimator createAnimator(final View target, final int viewPortWidth) {
+    if (target == null) {
+      return null;
+    }
+    WXAnimationBean.Style style = mAnimationBean.styles;
+    if (style != null) {
+      ObjectAnimator animator;
+      List<PropertyValuesHolder> holders = style.getHolders();
+      if (!TextUtils.isEmpty(style.backgroundColor)) {
+        BorderDrawable borderDrawable;
+        if ((borderDrawable = WXViewUtils.getBorderDrawable(target)) != null) {
+          holders.add(PropertyValuesHolder.ofObject(
+              new BackgroundColorProperty(), new ArgbEvaluator(),
+              borderDrawable.getColor(),
+              WXResourceUtils.getColor(style.backgroundColor)));
+        } else if (target.getBackground() instanceof ColorDrawable) {
+          holders.add(PropertyValuesHolder.ofObject(
+              new BackgroundColorProperty(), new ArgbEvaluator(),
+              ((ColorDrawable) target.getBackground()).getColor(),
+              WXResourceUtils.getColor(style.backgroundColor)));
+        }
+      }
+
+      if (target.getLayoutParams() != null &&
+          (!TextUtils.isEmpty(style.width) || !TextUtils.isEmpty(style.height))) {
+        ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
+        if (!TextUtils.isEmpty(style.width)) {
+          holders.add(PropertyValuesHolder.ofInt(new WidthProperty(), layoutParams.width,
+              (int) WXViewUtils.getRealPxByWidth(WXUtils.getFloat(style.width), viewPortWidth)));
+        }
+        if (!TextUtils.isEmpty(style.height)) {
+          holders.add(PropertyValuesHolder.ofInt(new HeightProperty(), layoutParams.height,
+              (int) WXViewUtils.getRealPxByWidth(WXUtils.getFloat(style.height), viewPortWidth)));
+        }
+      }
+
+      if (style.getPivot() != null) {
+        Pair<Float, Float> pair = style.getPivot();
+        target.setPivotX(pair.first);
+        target.setPivotY(pair.second);
+      }
+      animator = ObjectAnimator.ofPropertyValuesHolder(
+          target, holders.toArray(new PropertyValuesHolder[holders.size()]));
+      animator.setStartDelay(mAnimationBean.delay);
+      return animator;
+    } else {
+      return null;
+    }
+  }
+
+  private
+  @Nullable
+  Animator.AnimatorListener createAnimatorListener(final WXSDKInstance instance, @Nullable final String callBack) {
+    if (!TextUtils.isEmpty(callBack)) {
+      return new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+          if (instance == null || instance.isDestroy()) {
+            WXLogUtils.e("RenderContextImpl-onAnimationEnd WXSDKInstance == null NPE or instance is destroyed");
+          } else {
+            WXSDKManager.getInstance().callback(instance.getInstanceId(),
+                                                callBack,
+                                                new HashMap<String, Object>());
+          }
+        }
+      };
+    } else {
+      return null;
+    }
+  }
+
+  private
+  @Nullable
+  Interpolator createTimeInterpolator() {
+    String interpolator = mAnimationBean.timingFunction;
+    if (!TextUtils.isEmpty(interpolator)) {
+      switch (interpolator) {
+        case WXAnimationBean.EASE_IN:
+          return new AccelerateInterpolator();
+        case WXAnimationBean.EASE_OUT:
+          return new DecelerateInterpolator();
+        case WXAnimationBean.EASE_IN_OUT:
+          return new AccelerateDecelerateInterpolator();
+        case WXAnimationBean.LINEAR:
+          return new LinearInterpolator();
+        default:
+          //Parse cubic-bezier
+          try {
+            SingleFunctionParser<Float> parser = new SingleFunctionParser<>(
+                mAnimationBean.timingFunction,
+                new SingleFunctionParser.FlatMapper<Float>() {
+                  @Override
+                  public Float map(String raw) {
+                    return Float.parseFloat(raw);
+                  }
+                });
+            List<Float> params = parser.parse(WXAnimationBean.CUBIC_BEZIER);
+            if (params != null && params.size() == WXAnimationBean.NUM_CUBIC_PARAM) {
+              return PathInterpolatorCompat.create(
+                  params.get(0), params.get(1), params.get(2), params.get(3));
+            } else {
+              return null;
+            }
+          } catch (RuntimeException e) {
+            return null;
+          }
+      }
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAppendTreeCreateFinish.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAppendTreeCreateFinish.java
new file mode 100644
index 0000000..8e3a62e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionAppendTreeCreateFinish.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+
+/**
+ * Created by listen on 18/01/09.
+ */
+public class GraphicActionAppendTreeCreateFinish extends BasicGraphicAction {
+
+  WXComponent component;
+
+  public GraphicActionAppendTreeCreateFinish(WXSDKInstance instance, String ref) {
+    super(instance, ref);
+
+    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), ref);
+    if (null != component && component instanceof WXVContainer) {
+      ((WXVContainer)component).appendTreeCreateFinish();
+    }
+  }
+
+  @Override
+  public void executeAction() {
+
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchAction.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchAction.java
new file mode 100644
index 0000000..53cddfb
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchAction.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GraphicActionBatchAction extends BasicGraphicAction {
+    private List<BasicGraphicAction> mActions;
+
+    public GraphicActionBatchAction(WXSDKInstance instance, String ref, List<BasicGraphicAction> mActions) {
+        super(instance, ref);
+        this.mActions = new ArrayList<>(mActions);
+    }
+
+    @Override
+    public void executeAction() {
+        for (int i = 0;i < mActions.size();i ++) {
+            mActions.get(i).executeAction();
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchBegin.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchBegin.java
new file mode 100644
index 0000000..e99772d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchBegin.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+
+public class GraphicActionBatchBegin extends BasicGraphicAction {
+    public GraphicActionBatchBegin(WXSDKInstance instance, String ref) {
+        super(instance, ref);
+        this.mActionType = ActionTypeBatchBegin;
+    }
+
+    @Override
+    public void executeAction() {
+
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchEnd.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchEnd.java
new file mode 100644
index 0000000..3ba8355
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionBatchEnd.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+
+public class GraphicActionBatchEnd extends BasicGraphicAction {
+    public GraphicActionBatchEnd(WXSDKInstance instance, String ref) {
+        super(instance, ref);
+        this.mActionType = ActionTypeBatchEnd;
+    }
+
+    @Override
+    public void executeAction() {
+
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionCreateBody.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionCreateBody.java
new file mode 100644
index 0000000..dad6032
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionCreateBody.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+import android.widget.ScrollView;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.dom.transition.WXTransition;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXScroller;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.Map;
+import java.util.Set;
+
+public class GraphicActionCreateBody extends GraphicActionAbstractAddElement {
+
+  private WXComponent component;
+
+  public GraphicActionCreateBody(@NonNull WXSDKInstance instance, String ref,
+                                 String componentType,
+                                 Map<String, String> style,
+                                 Map<String, String> attributes,
+                                 Set<String> events,
+                                 float[] margins,
+                                 float[] paddings,
+                                 float[] borders) {
+    super(instance, ref);
+    this.mComponentType = componentType;
+    this.mStyle = style;
+    this.mAttributes = attributes;
+    this.mEvents = events;
+    this.mMargins = margins;
+    this.mPaddings = paddings;
+    this.mBorders = borders;
+
+    if (instance.getContext() == null) {
+      return;
+    }
+
+    BasicComponentData basicComponentData = new BasicComponentData(getRef(), mComponentType, null);
+    component = createComponent(instance, null, basicComponentData);
+    if (component == null) {
+      return;
+    }
+    component.setTransition(WXTransition.fromMap(component.getStyles(), component));
+  }
+
+  @Override
+  public void executeAction() {
+    super.executeAction();
+    try {
+      component.createView();
+      component.applyLayoutAndEvent(component);
+      component.bindData(component);
+      WXSDKInstance instance = getWXSDKIntance();
+
+      if (component instanceof WXScroller) {
+        WXScroller scroller = (WXScroller) component;
+        if (scroller.getInnerView() instanceof ScrollView) {
+          instance.setRootScrollView((ScrollView) scroller.getInnerView());
+        }
+      }
+
+      instance.onRootCreated(component);
+
+      if (instance.getRenderStrategy() != WXRenderStrategy.APPEND_ONCE) {
+        instance.onCreateFinish();
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("create body failed.", e);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionCreateFinish.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionCreateFinish.java
new file mode 100644
index 0000000..717934f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionCreateFinish.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.RenderTypes;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by listen on 18/01/09.
+ */
+public class GraphicActionCreateFinish extends BasicGraphicAction {
+
+  private int mLayoutWidth;
+  private int mLayoutHeight;
+
+  public GraphicActionCreateFinish(@NonNull WXSDKInstance instance) {
+    super(instance, "");
+    WXComponent component = instance.getRootComponent();
+    if (null != component) {
+        this.mLayoutWidth = (int) component.getLayoutWidth();
+        this.mLayoutHeight = (int) component.getLayoutHeight();
+    }
+    instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_CREATE_FINISH);
+    instance.getApmForInstance().extInfo.put(WXInstanceApm.KEY_PAGE_STAGES_CREATE_FINISH,true);
+  }
+
+  @Override
+  public void executeAction() {
+    final WXSDKInstance instance = getWXSDKIntance();
+    if (instance == null || instance.getContext() == null) {
+      return;
+    }
+    if(instance.mHasCreateFinish){
+        return;
+    }
+
+    if (instance.getRenderStrategy() == WXRenderStrategy.APPEND_ONCE) {
+      instance.onCreateFinish();
+    }else{
+      if(!RenderTypes.RENDER_TYPE_NATIVE.equals(instance.getRenderType())){
+          instance.onCreateFinish();
+      }
+    }
+
+    instance.mHasCreateFinish = true;
+
+    if (null != instance.getWXPerformance()){
+      instance.getWXPerformance().callCreateFinishTime = System.currentTimeMillis()-instance.getWXPerformance().renderTimeOrigin;
+    }
+    instance.onOldFsRenderTimeLogic();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionLayout.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionLayout.java
new file mode 100644
index 0000000..c2c2c0c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionLayout.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.WXComponent;
+
+public class GraphicActionLayout extends BasicGraphicAction {
+
+  private final GraphicPosition mLayoutPosition;
+  private final GraphicSize mLayoutSize;
+  private final boolean mIsLayoutRTL;
+
+  public GraphicActionLayout(WXSDKInstance instance, String ref, GraphicPosition layoutPosition, GraphicSize layoutSize, boolean isRTL) {
+    super(instance, ref);
+    this.mLayoutPosition = layoutPosition;
+    this.mLayoutSize = layoutSize;
+    this.mIsLayoutRTL = isRTL;
+  }
+
+  @Override
+  public void executeAction() {
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      return;
+    }
+
+    component.setIsLayoutRTL(mIsLayoutRTL);
+    component.setDemission(mLayoutSize, mLayoutPosition);
+    component.setSafeLayout(component);
+    component.setPadding(component.getPadding(), component.getBorder());
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionMoveElement.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionMoveElement.java
new file mode 100644
index 0000000..4c38840
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionMoveElement.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+
+public class GraphicActionMoveElement extends BasicGraphicAction {
+
+  private String mParentref;
+  private int mIndex;
+
+  public GraphicActionMoveElement(WXSDKInstance instance, String ref, String parentRef, int index) {
+    super(instance, ref);
+    this.mParentref = parentRef;
+    this.mIndex = index;
+  }
+
+  @Override
+  public void executeAction() {
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if(component == null) {
+      return;
+    }
+    WXVContainer oldParent = component.getParent();
+    WXComponent newParent = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), mParentref);
+    if (oldParent == null
+            || newParent == null || !(newParent instanceof WXVContainer)) {
+      return;
+    }
+
+    if (component.getHostView() != null && !TextUtils.equals(component.getComponentType(), "video") && !TextUtils.equals(component.getComponentType(), "videoplus")) {
+      int[] location = new  int[2] ;
+      component.getHostView().getLocationInWindow(location);
+    }
+
+    oldParent.remove(component, false);
+
+    ((WXVContainer) newParent).addChild(component, mIndex);
+
+    if (component.getHostView() != null && !TextUtils.equals(component.getComponentType(), "video") && !TextUtils.equals(component.getComponentType(), "videoplus")) {
+      int[] location = new  int[2] ;
+      component.getHostView().getLocationInWindow(location);
+    }
+
+    if (!component.isVirtualComponent()) {
+      ((WXVContainer) newParent).addSubView(component.getHostView(), mIndex);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRefreshFinish.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRefreshFinish.java
new file mode 100644
index 0000000..3f6fde7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRefreshFinish.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by listen on 18/01/09.
+ */
+public class GraphicActionRefreshFinish extends BasicGraphicAction {
+
+  private int mLayoutWidth;
+  private int mLayoutHeight;
+
+  public GraphicActionRefreshFinish(@NonNull WXSDKInstance instance) {
+    super(instance, "");
+    WXComponent component = instance.getRootComponent();
+    if (null != component) {
+        this.mLayoutWidth = (int) component.getLayoutWidth();
+        this.mLayoutHeight = (int) component.getLayoutHeight();
+    }
+  }
+
+  @Override
+  public void executeAction() {
+    final WXSDKInstance instance = getWXSDKIntance();
+    if (instance == null || instance.getContext() == null) {
+      return;
+    }
+
+    instance.onRefreshSuccess(mLayoutWidth, mLayoutHeight);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveChildFromRichtext.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveChildFromRichtext.java
new file mode 100755
index 0000000..0c405fc
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveChildFromRichtext.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.richtext.WXRichText;
+
+public class GraphicActionRemoveChildFromRichtext extends BasicGraphicAction{
+    private String ref;
+    private String parentRef;
+    private WXRichText richText;
+    public GraphicActionRemoveChildFromRichtext(WXSDKInstance instance,String ref,String parentRef,String richtextRef){
+        super(instance, richtextRef);
+        this.ref = ref;
+        this.parentRef = parentRef;
+        richText = (WXRichText) WXSDKManager.getInstance().getWXRenderManager().
+                getWXComponent(instance.getInstanceId(),richtextRef);
+        if(richText != null){
+            richText.removeChildNode(parentRef,ref);
+        }
+    }
+    @Override
+    public void executeAction() {
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveElement.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveElement.java
new file mode 100644
index 0000000..abf4a8b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveElement.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+
+public class GraphicActionRemoveElement extends BasicGraphicAction {
+
+  public GraphicActionRemoveElement(WXSDKInstance instance, String ref) {
+    super(instance, ref);
+  }
+
+  @Override
+  public void executeAction() {
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null || component.getParent() == null || component.getInstance() == null) {
+      return;
+    }
+    clearRegistryForComponent(component);
+    WXVContainer parent = component.getParent();
+
+    if (component.getHostView() != null && !TextUtils.equals(component.getComponentType(), "video") && !TextUtils.equals(component.getComponentType(), "videoplus")) {
+      int[] location = new  int[2];
+      component.getHostView().getLocationInWindow(location);
+      //component.getInstance().onChangeElement(parent, location[1] > component.getInstance().getWeexHeight() + 1);
+    }
+
+    parent.remove(component, true);
+  }
+
+  private void clearRegistryForComponent(WXComponent component) {
+    WXComponent removedComponent = WXSDKManager.getInstance().getWXRenderManager().unregisterComponent(getPageId(), getRef());
+    if (removedComponent != null) {
+      removedComponent.removeAllEvent();
+      removedComponent.removeStickyStyle();
+    }
+    if (component instanceof WXVContainer) {
+      WXVContainer container = (WXVContainer) component;
+      int count = container.childCount();
+      for (int i = count - 1; i >= 0; --i) {
+        clearRegistryForComponent(container.getChild(i));
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveEvent.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveEvent.java
new file mode 100644
index 0000000..5727044
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRemoveEvent.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.tracing.Stopwatch;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by listen on 18/01/11.
+ */
+public class GraphicActionRemoveEvent extends BasicGraphicAction {
+
+  private final String mEvent;
+
+  public GraphicActionRemoveEvent(WXSDKInstance instance, String ref, Object event) {
+    super(instance, ref);
+    this.mEvent = WXEvent.getEventName(event);
+  }
+
+  @Override
+  public void executeAction() {
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      return;
+    }
+
+    Stopwatch.tick();
+    component.removeEvent(mEvent);
+    Stopwatch.split("removeEventFromComponent");
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRenderSuccess.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRenderSuccess.java
new file mode 100644
index 0000000..8c8615f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionRenderSuccess.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.annotation.NonNull;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.component.WXComponent;
+
+public class GraphicActionRenderSuccess extends BasicGraphicAction {
+
+    public GraphicActionRenderSuccess(@NonNull WXSDKInstance instance) {
+        super(instance, "");
+    }
+
+    @Override
+    public void executeAction() {
+        final WXSDKInstance instance = getWXSDKIntance();
+        if (instance == null || instance.getContext() == null) {
+            return;
+        }
+        WXComponent component = instance.getRootComponent();
+        int layoutWidth = 0;
+        int layoutHeight = 0;
+        if (null != component) {
+            layoutWidth = (int) component.getLayoutWidth();
+            layoutHeight = (int) component.getLayoutHeight();
+        }
+        instance.onRenderSuccess(layoutWidth, layoutHeight);
+    }
+
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionScrollToElement.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionScrollToElement.java
new file mode 100644
index 0000000..5a4b809
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionScrollToElement.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.Scrollable;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by listen on 18/01/09.
+ */
+public class GraphicActionScrollToElement extends BasicGraphicAction {
+
+  private final JSONObject mOptions;
+
+  public GraphicActionScrollToElement(WXSDKInstance instance, String ref, JSONObject options) {
+    super(instance, ref);
+    this.mOptions = options;
+  }
+
+  @Override
+  public void executeAction() {
+    WXComponent component = WXSDKManager
+        .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      return;
+    }
+
+    Scrollable scroller = component.getParentScroller();
+    if (scroller == null) {
+      return;
+    }
+    scroller.scrollTo(component, mOptions);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateAttr.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateAttr.java
new file mode 100644
index 0000000..d7713ce
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateAttr.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.WXComponent;
+
+import java.util.Map;
+
+public class GraphicActionUpdateAttr extends BasicGraphicAction {
+
+  private Map<String, String> mAttrs;
+  private WXComponent component;
+
+  public GraphicActionUpdateAttr(WXSDKInstance instance, String ref,
+                                 Map<String, String> attrs) {
+    super(instance, ref);
+    this.mAttrs = attrs;
+
+    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      return;
+    }
+    if (mAttrs != null) {
+      component.addAttr(mAttrs);
+    }
+  }
+
+  @Override
+  public void executeAction() {
+    if (component == null) {
+      return;
+    }
+    component.getAttrs().mergeAttr();
+    component.updateAttrs(mAttrs);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateRichtextAttr.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateRichtextAttr.java
new file mode 100755
index 0000000..19b896b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateRichtextAttr.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.richtext.WXRichText;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GraphicActionUpdateRichtextAttr extends BasicGraphicAction{
+
+    public GraphicActionUpdateRichtextAttr(WXSDKInstance instance, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef){
+        super(instance, richTextRef);
+        WXRichText richText =  (WXRichText) WXSDKManager.getInstance().getWXRenderManager()
+                .getWXComponent(getPageId(), richTextRef);
+        if(richText != null) {
+            Map<String, Object> map = new HashMap<>();
+            map.putAll(attrs);
+            richText.updateChildNodeAttrs(ref, map);
+        }
+    }
+    @Override
+    public void executeAction() {
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateRichtextStyle.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateRichtextStyle.java
new file mode 100755
index 0000000..b9cc2e5
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateRichtextStyle.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.richtext.WXRichText;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class GraphicActionUpdateRichtextStyle  extends BasicGraphicAction{
+    public GraphicActionUpdateRichtextStyle(WXSDKInstance instance, String ref, HashMap<String, String> styles, String parentRef, String richTextRef){
+        super(instance, richTextRef);
+        WXRichText richText =  (WXRichText) WXSDKManager.getInstance().getWXRenderManager()
+                .getWXComponent(getPageId(), richTextRef);
+        if(richText != null){
+                Map<String, Object> map = new HashMap<>();
+                map.putAll(styles);
+                richText.updateChildNodeStyles(ref, map);
+
+        }
+    }
+    @Override
+    public void executeAction() {
+
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateStyle.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateStyle.java
new file mode 100644
index 0000000..fd9e999
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicActionUpdateStyle.java
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.support.v4.util.ArrayMap;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.dom.transition.WXTransition;
+import org.apache.weex.ui.component.WXComponent;
+
+import java.util.Map;
+
+public class GraphicActionUpdateStyle extends BasicGraphicAction {
+
+  private Map<String, Object> mStyle;
+  private WXComponent component;
+  private boolean mIsCausedByPesudo;
+  private boolean mIsBorderSet;
+
+  public GraphicActionUpdateStyle(WXSDKInstance instance, String ref,
+                                  Map<String, Object> style,
+                                  Map<String, String> paddings,
+                                  Map<String, String> margins,
+                                  Map<String, String> borders) {
+    this(instance, ref, style, paddings, margins, borders, false);
+  }
+
+  public GraphicActionUpdateStyle(WXSDKInstance instance, String ref,
+                                  Map<String, Object> style,
+                                  CSSShorthand paddings,
+                                  CSSShorthand margins,
+                                  CSSShorthand borders, boolean byPesudo) {
+    super(instance, ref);
+    this.mStyle = style;
+    this.mIsCausedByPesudo = byPesudo;
+
+    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      return;
+    }
+    if (null != mStyle) {
+      component.updateStyle(mStyle, mIsCausedByPesudo);
+      if(style.containsKey(Constants.Name.TRANSFORM) && component.getTransition() == null) {
+        Map<String, Object> animationMap = new ArrayMap<>(2);
+        animationMap.put(Constants.Name.TRANSFORM, style.get(Constants.Name.TRANSFORM));
+        animationMap
+            .put(Constants.Name.TRANSFORM_ORIGIN, style.get(Constants.Name.TRANSFORM_ORIGIN));
+        component.addAnimationForElement(animationMap);
+      }
+    }
+
+    if (null != paddings) {
+      component.setPaddings(paddings);
+    }
+
+    if (null != margins) {
+      component.setMargins(margins);
+    }
+
+    if (null != borders) {
+      mIsBorderSet = true;
+      component.setBorders(borders);
+    }
+  }
+
+  public GraphicActionUpdateStyle(WXSDKInstance instance, String ref,
+                                  Map<String, Object> style,
+                                  Map<String, String> paddings,
+                                  Map<String, String> margins,
+                                  Map<String, String> borders, boolean byPesudo) {
+    super(instance, ref);
+    this.mStyle = style;
+    this.mIsCausedByPesudo = byPesudo;
+
+    component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+    if (component == null) {
+      return;
+    }
+    if (null != mStyle) {
+      component.addStyle(mStyle, mIsCausedByPesudo);
+      if(style.containsKey(Constants.Name.TRANSFORM) && component.getTransition() == null){
+        Map<String, Object> animationMap = new ArrayMap<>(2);
+        animationMap.put(Constants.Name.TRANSFORM, style.get(Constants.Name.TRANSFORM));
+        animationMap.put(Constants.Name.TRANSFORM_ORIGIN, style.get(Constants.Name.TRANSFORM_ORIGIN));
+        component.addAnimationForElement(animationMap);
+        WXBridgeManager.getInstance().markDirty(component.getInstanceId(), component.getRef(), true);
+      }
+    }
+
+    if (null != paddings) {
+      component.addShorthand(paddings);
+    }
+
+    if (null != margins) {
+      component.addShorthand(margins);
+    }
+
+    if (null != borders) {
+      mIsBorderSet = true;
+      component.addShorthand(borders);
+    }
+  }
+
+  @Override
+  public void executeAction() {
+    if (component == null) return;
+    if (mStyle != null) {
+      if(component.getTransition() != null){
+        component.getTransition().updateTranstionParams(mStyle);
+        if(component.getTransition().hasTransitionProperty(mStyle)){
+          component.getTransition().startTransition(mStyle);
+        }
+      } else {
+        component.setTransition(WXTransition.fromMap(mStyle, component));
+        component.updateStyles(mStyle);
+      }
+    } else if (mIsBorderSet) {
+      component.updateStyles(component);
+    }
+  }
+}
+
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicPosition.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicPosition.java
new file mode 100644
index 0000000..5796caf
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicPosition.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+public class GraphicPosition {
+
+  private float mLeft;
+  private float mTop;
+  private float mRight;
+  private float mBottom;
+
+  public GraphicPosition(float left, float top, float right, float bottom) {
+    this.mLeft = left;
+    this.mTop = top;
+    this.mRight = right;
+    this.mBottom = bottom;
+  }
+
+  public float getLeft() {
+    return mLeft;
+  }
+
+  public void setLeft(float left) {
+    this.mLeft = left;
+  }
+
+  public float getTop() {
+    return mTop;
+  }
+
+  public void setTop(float top) {
+    this.mTop = top;
+  }
+
+  public float getRight() {
+    return mRight;
+  }
+
+  public void setRight(float right) {
+    this.mRight = right;
+  }
+
+  public float getBottom() {
+    return mBottom;
+  }
+
+  public void setBottom(float bottom) {
+    this.mBottom = bottom;
+  }
+
+
+  public void update(float top, float bottom, float left, float right) {
+    this.mTop = top;
+    this.mBottom = bottom;
+    this.mLeft = left;
+    this.mRight = right;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicSize.java b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicSize.java
new file mode 100644
index 0000000..f523644
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/GraphicSize.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+public class GraphicSize {
+
+  private float mWidth;
+  private float mHeight;
+
+  public GraphicSize(float width, float height) {
+    this.mWidth = width;
+    this.mHeight = height;
+  }
+
+  public float getWidth() {
+    return mWidth;
+  }
+
+  public void setWidth(float width) {
+    this.mWidth = width;
+  }
+
+  public float getHeight() {
+    return mHeight;
+  }
+
+  public void setHeight(float height) {
+    this.mHeight = height;
+  }
+
+  public void update(float width, float height) {
+    this.mWidth = width;
+    this.mHeight = height;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/IExecutable.java b/android/sdk/src/main/java/org/apache/weex/ui/action/IExecutable.java
new file mode 100644
index 0000000..c140e49
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/IExecutable.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+public interface IExecutable {
+
+  void executeAction();
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/action/UpdateComponentDataAction.java b/android/sdk/src/main/java/org/apache/weex/ui/action/UpdateComponentDataAction.java
new file mode 100644
index 0000000..ef14a2e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/action/UpdateComponentDataAction.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.action;
+
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.SimpleJSCallback;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.list.template.CellDataManager;
+import org.apache.weex.ui.component.list.template.WXRecyclerTemplateList;
+import org.apache.weex.utils.WXLogUtils;
+
+
+/**
+ * Created by furture on 2018/1/23.
+ */
+
+public class UpdateComponentDataAction extends BasicGraphicAction{
+
+    private String virtualComponentId;
+    private JSONObject data;
+    private String callback;
+
+
+    public UpdateComponentDataAction(WXSDKInstance instance, String virtualComponentId,
+                                     JSONObject data, String callback) {
+        super(instance, CellDataManager.getListRef(virtualComponentId));
+        this.virtualComponentId = virtualComponentId;
+        this.data = data;
+        this.callback = callback;
+    }
+
+    @Override
+    public void executeAction() {
+        if(TextUtils.isEmpty(getRef())){
+            WXLogUtils.e("wrong virtualComponentId split error " + virtualComponentId);
+            return;
+        }
+        WXComponent component = WXSDKManager
+            .getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+        if(component instanceof WXRecyclerTemplateList){
+            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) component;
+            templateList.getCellDataManager().updateVirtualComponentData(virtualComponentId, data);
+            templateList.notifyUpdateList();
+            SimpleJSCallback jsCallback = new SimpleJSCallback(component.getInstanceId(), callback);
+            jsCallback.invoke(true);
+        }else{
+            WXLogUtils.e("recycler-list wrong virtualComponentId " + virtualComponentId);
+        }
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/BackgroundColorProperty.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/BackgroundColorProperty.java
new file mode 100644
index 0000000..b6eab01
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/BackgroundColorProperty.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.util.Property;
+import android.view.View;
+
+import org.apache.weex.ui.view.border.BorderDrawable;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+public class BackgroundColorProperty extends Property<View, Integer> {
+
+  private final static String TAG = "BackgroundColorAnimation";
+
+  public BackgroundColorProperty() {
+    super(Integer.class, WXAnimationBean.Style.BACKGROUND_COLOR);
+  }
+
+  @Override
+  public Integer get(View object) {
+    int color;
+    BorderDrawable borderDrawable;
+    if ((borderDrawable = WXViewUtils.getBorderDrawable(object)) != null) {
+      color = borderDrawable.getColor();
+    } else if (object.getBackground() instanceof ColorDrawable) {
+      color = ((ColorDrawable) object.getBackground()).getColor();
+    } else {
+      color = Color.TRANSPARENT;
+      WXLogUtils.e(TAG, "Unsupported background type");
+    }
+    return color;
+  }
+
+  @Override
+  public void set(View object, Integer value) {
+    BorderDrawable borderDrawable;
+    if ((borderDrawable = WXViewUtils.getBorderDrawable(object)) != null) {
+      borderDrawable.setColor(value);
+    } else if (object.getBackground() instanceof ColorDrawable) {
+      ((ColorDrawable) object.getBackground()).setColor(value);
+    } else {
+      WXLogUtils.e(TAG, "Unsupported background type");
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/CameraDistanceProperty.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/CameraDistanceProperty.java
new file mode 100644
index 0000000..5024388
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/CameraDistanceProperty.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.util.Property;
+import android.view.View;
+
+
+class CameraDistanceProperty extends Property<View, Float> {
+
+  private final static String TAG = "CameraDistance";
+  private static CameraDistanceProperty instance;
+
+  static Property<View, Float> getInstance(){
+    return instance;
+  }
+
+  private CameraDistanceProperty() {
+    super(Float.class, TAG);
+  }
+
+  @Override
+  public Float get(View view) {
+    if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+      return view.getCameraDistance();
+    }
+    else{
+      return Float.NaN;
+    }
+  }
+
+  @Override
+  public void set(View object, Float value) {
+    object.setCameraDistance(value);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/HeightProperty.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/HeightProperty.java
new file mode 100644
index 0000000..9fc404e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/HeightProperty.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+
+import android.view.ViewGroup.LayoutParams;
+
+public class HeightProperty extends LayoutParamsProperty {
+
+  @Override
+  protected Integer getProperty(LayoutParams layoutParams) {
+    return layoutParams.height;
+  }
+
+  @Override
+  protected void setProperty(LayoutParams layoutParams, Integer expected) {
+    layoutParams.height = expected;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/LayoutParamsProperty.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/LayoutParamsProperty.java
new file mode 100644
index 0000000..f4ef1d7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/LayoutParamsProperty.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+
+import android.util.Property;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.view.IRenderResult;
+
+/**
+ * android.util.IntProperty<T> cannot be applied here, as it is only added at API 24.
+ */
+abstract class LayoutParamsProperty extends Property<View, Integer> {
+
+  LayoutParamsProperty() {
+    super(Integer.class, "layoutParams");
+  }
+
+  @Override
+  public Integer get(View object) {
+    LayoutParams layoutParams;
+    if (object != null && (layoutParams = object.getLayoutParams()) != null) {
+      return getProperty(layoutParams);
+    }
+    return 0;
+  }
+
+  @Override
+  public void set(View object, Integer value) {
+    LayoutParams layoutParams;
+    if (object != null && (layoutParams = object.getLayoutParams()) != null) {
+      setProperty(layoutParams, value);
+      if (object instanceof IRenderResult) {
+        WXComponent component = ((IRenderResult) object).getComponent();
+        if (component != null) {
+            component.notifyNativeSizeChanged(layoutParams.width, layoutParams.height);
+        }
+      }
+      object.requestLayout();
+    }
+  }
+
+  protected abstract Integer getProperty(LayoutParams layoutParams);
+
+  protected abstract void setProperty(LayoutParams layoutParams, Integer expected);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/TransformParser.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/TransformParser.java
new file mode 100644
index 0000000..9087fab
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/TransformParser.java
@@ -0,0 +1,310 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+import android.animation.PropertyValuesHolder;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Property;
+import android.view.View;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.utils.FunctionParser;
+import org.apache.weex.utils.WXDataStructureUtil;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by furture on 2017/10/24.
+ */
+
+public class TransformParser {
+
+    public final static String WX_TRANSLATE = "translate";
+    public final static String WX_TRANSLATE_X = "translateX";
+    public final static String WX_TRANSLATE_Y = "translateY";
+    public final static String WX_ROTATE = "rotate";
+    public final static String WX_ROTATE_X ="rotateX";
+    public final static String WX_ROTATE_Y ="rotateY";
+    public final static String WX_ROTATE_Z ="rotateZ";
+    public final static String WX_SCALE = "scale";
+    public final static String WX_SCALE_X = "scaleX";
+    public final static String WX_SCALE_Y = "scaleY";
+
+    public final static String BACKGROUND_COLOR = Constants.Name.BACKGROUND_COLOR;
+    public final static String WIDTH = Constants.Name.WIDTH;
+    public final static String HEIGHT = Constants.Name.HEIGHT;
+    public final static String TOP = "top";
+    public final static String BOTTOM = "bottom";
+    public final static String RIGHT = "right";
+    public final static String LEFT = "left";
+    public final static String CENTER = "center";
+    private static final String HALF = "50%";
+    private static final String FULL = "100%";
+    private static final String ZERO = "0%";
+    private static final String PX = "px";
+    private static final String DEG = "deg";
+    public static Map<String, List<Property<View,Float>>> wxToAndroidMap = new ArrayMap<>();
+
+
+    static {
+        wxToAndroidMap.put(WX_TRANSLATE, Arrays.asList
+                (View.TRANSLATION_X, View.TRANSLATION_Y));
+        wxToAndroidMap.put(WX_TRANSLATE_X, Collections.singletonList(View.TRANSLATION_X));
+        wxToAndroidMap.put(WX_TRANSLATE_Y, Collections.singletonList(View.TRANSLATION_Y));
+        wxToAndroidMap.put(WX_ROTATE, Collections.singletonList(View.ROTATION));
+        wxToAndroidMap.put(WX_ROTATE_Z, Collections.singletonList(View.ROTATION));
+        wxToAndroidMap.put(WX_ROTATE_X, Collections.singletonList(View.ROTATION_X));
+        wxToAndroidMap.put(WX_ROTATE_Y, Collections.singletonList(View.ROTATION_Y));
+        wxToAndroidMap.put(WX_SCALE, Arrays.asList(View.SCALE_X, View.SCALE_Y));
+        wxToAndroidMap.put(WX_SCALE_X, Collections.singletonList(View.SCALE_X));
+        wxToAndroidMap.put(WX_SCALE_Y, Collections.singletonList(View.SCALE_Y));
+        wxToAndroidMap.put(Constants.Name.PERSPECTIVE, Collections.singletonList(CameraDistanceProperty.getInstance()));
+        wxToAndroidMap = Collections.unmodifiableMap(wxToAndroidMap);
+    }
+
+    public static PropertyValuesHolder[] toHolders(Map<Property<View,Float>, Float> transformMap){
+        PropertyValuesHolder[]  holders = new PropertyValuesHolder[transformMap.size()];
+        int i=0;
+        for (Map.Entry<Property<View, Float>, Float> entry : transformMap.entrySet()) {
+            holders[i] = PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue());
+            i++;
+        }
+        return holders;
+    }
+
+    public static Map<Property<View,Float>, Float> parseTransForm(String instanceId, @Nullable String rawTransform, final int width,
+                                                                  final int height, final int viewportW) {
+        try{
+
+            if (!TextUtils.isEmpty(rawTransform)) {
+                FunctionParser<Property<View,Float>, Float> parser = new FunctionParser<>
+                        (rawTransform, new FunctionParser.Mapper<Property<View,Float>, Float>() {
+                            @Override
+                            public Map<Property<View,Float>, Float> map(String functionName, List<String> raw) {
+                                if (raw != null && !raw.isEmpty()) {
+                                    if (wxToAndroidMap.containsKey(functionName)) {
+                                        return convertParam(width, height,viewportW, wxToAndroidMap.get(functionName), raw);
+                                    }
+                                }
+                                return new HashMap<>();
+                            }
+
+                            private Map<Property<View,Float>, Float> convertParam(int width, int height, int viewportW,
+                                                                                  @NonNull List<Property<View,Float>> propertyList,
+                                                                                  @NonNull List<String> rawValue) {
+
+                                Map<Property<View,Float>, Float> result = WXDataStructureUtil.newHashMapWithExpectedSize(propertyList.size());
+                                List<Float> convertedList = new ArrayList<>(propertyList.size());
+                                if (propertyList.contains(View.ROTATION) ||
+                                        propertyList.contains(View.ROTATION_X) ||
+                                        propertyList.contains(View.ROTATION_Y)) {
+                                    convertedList.addAll(parseRotationZ(rawValue));
+                                }else if (propertyList.contains(View.TRANSLATION_X) ||
+                                        propertyList.contains(View.TRANSLATION_Y)) {
+                                    convertedList.addAll(parseTranslation(propertyList, width, height, rawValue,viewportW));
+                                } else if (propertyList.contains(View.SCALE_X) ||
+                                        propertyList.contains(View.SCALE_Y)) {
+                                    convertedList.addAll(parseScale(propertyList.size(), rawValue));
+                                }
+                                else if(propertyList.contains(CameraDistanceProperty.getInstance())){
+                                    convertedList.add(parseCameraDistance(rawValue));
+                                }
+                                if (propertyList.size() == convertedList.size()) {
+                                    for (int i = 0; i < propertyList.size(); i++) {
+                                        result.put(propertyList.get(i), convertedList.get(i));
+                                    }
+                                }
+                                return result;
+                            }
+
+                            private List<Float> parseScale(int size, @NonNull List<String> rawValue) {
+                                List<Float> convertedList = new ArrayList<>(rawValue.size() * 2);
+                                List<Float> rawFloat = new ArrayList<>(rawValue.size());
+                                for (String item : rawValue) {
+                                    rawFloat.add(WXUtils.fastGetFloat(item));
+                                }
+                                convertedList.addAll(rawFloat);
+                                if (size != 1 && rawValue.size() == 1) {
+                                    convertedList.addAll(rawFloat);
+                                }
+                                return convertedList;
+                            }
+
+                            private @NonNull
+                            List<Float> parseRotationZ(@NonNull List<String> rawValue) {
+                                List<Float> convertedList = new ArrayList<>(1);
+                                int suffix;
+                                for (String raw : rawValue) {
+                                    if ((suffix = raw.lastIndexOf(DEG)) != -1) {
+                                        convertedList.add(WXUtils.fastGetFloat(raw.substring(0, suffix)));
+                                    } else {
+                                        convertedList.add((float) Math.toDegrees(WXUtils.fastGetFloat(raw)));
+                                    }
+                                }
+                                return convertedList;
+                            }
+
+                            /**
+                             * As "translate(50%, 25%)" or "translate(25px, 30px)" both are valid,
+                             * parsing translate is complicated than other method.
+                             * Add your waste time here if you try to optimize this method like {@link #parseScale(int, List)}
+                             * Time: 0.5h
+                             */
+                            private List<Float> parseTranslation(List<Property<View,Float>> propertyList,
+                                                                 int width, int height,
+                                                                 @NonNull List<String> rawValue, int viewportW) {
+                                List<Float> convertedList = new ArrayList<>(2);
+                                String first = rawValue.get(0);
+                                if (propertyList.size() == 1) {
+                                    parseSingleTranslation(propertyList, width, height, convertedList, first,viewportW);
+                                } else {
+                                    parseDoubleTranslation(width, height, rawValue, convertedList, first,viewportW);
+                                }
+                                return convertedList;
+                            }
+
+                            private void parseSingleTranslation(List<Property<View,Float>> propertyList, int width, int height,
+                                                                List<Float> convertedList, String first, int viewportW) {
+                                if (propertyList.contains(View.TRANSLATION_X)) {
+                                    convertedList.add(parsePercentOrPx(first, width,viewportW));
+                                } else if (propertyList.contains(View.TRANSLATION_Y)) {
+                                    convertedList.add(parsePercentOrPx(first, height,viewportW));
+                                }
+                            }
+
+                            private void parseDoubleTranslation(int width, int height,
+                                                                @NonNull List<String> rawValue,
+                                                                List<Float> convertedList, String first, int viewportW) {
+                                String second;
+                                if (rawValue.size() == 1) {
+                                    second = first;
+                                } else {
+                                    second = rawValue.get(1);
+                                }
+                                convertedList.add(parsePercentOrPx(first, width,viewportW));
+                                convertedList.add(parsePercentOrPx(second, height,viewportW));
+                            }
+
+                            private Float parseCameraDistance(List<String> rawValue){
+                                float ret= Float.MAX_VALUE;
+                                if(rawValue.size() == 1){
+                                    float value = WXViewUtils.getRealPxByWidth(WXUtils.getFloat(rawValue.get(0)), viewportW);
+                                    float scale = WXEnvironment.getApplication().getResources().getDisplayMetrics().density;
+                                    if (!Float.isNaN(value) && value > 0) {
+                                        ret = value * scale;
+                                    }
+                                }
+                                return ret;
+                            }
+                        });
+                return parser.parse();
+            }
+        }catch (Exception e){
+            WXLogUtils.e("TransformParser", e);
+            WXExceptionUtils.commitCriticalExceptionRT(instanceId,
+                    WXErrorCode.WX_RENDER_ERR_TRANSITION,
+                    "parse animation transition",
+                    WXErrorCode.WX_RENDER_ERR_TRANSITION.getErrorMsg() + "parse transition error: " +  e.getMessage(),
+                    null);
+        }
+        return new LinkedHashMap<>();
+    }
+
+    private static Pair<Float, Float> parsePivot(@Nullable String transformOrigin,
+                                                 int width, int height, int viewportW) {
+        if (!TextUtils.isEmpty(transformOrigin)) {
+            int firstSpace = transformOrigin.indexOf(FunctionParser.SPACE);
+            if (firstSpace != -1) {
+                int i = firstSpace;
+                for (; i < transformOrigin.length(); i++) {
+                    if (transformOrigin.charAt(i) != FunctionParser.SPACE) {
+                        break;
+                    }
+                }
+                if (i < transformOrigin.length() && transformOrigin.charAt(i) != FunctionParser.SPACE) {
+                    List<String> list = new ArrayList<>(2);
+                    list.add(transformOrigin.substring(0, firstSpace).trim());
+                    list.add(transformOrigin.substring(i, transformOrigin.length()).trim());
+                    return parsePivot(list, width, height,viewportW);
+                }
+            }
+        }
+        return null;
+    }
+
+    private static Pair<Float, Float> parsePivot(@NonNull List<String> list, int width, int height, int viewportW) {
+        return new Pair<>(
+                parsePivotX(list.get(0), width,viewportW), parsePivotY(list.get(1), height,viewportW));
+    }
+
+    private static float parsePivotX(String x, int width, int viewportW) {
+        String value = x;
+        if (WXAnimationBean.Style.LEFT.equals(x)) {
+            value = ZERO;
+        } else if (WXAnimationBean.Style.RIGHT.equals(x)) {
+            value = FULL;
+        } else if (WXAnimationBean.Style.CENTER.equals(x)) {
+            value = HALF;
+        }
+        return parsePercentOrPx(value, width,viewportW);
+    }
+
+    private static float parsePivotY(String y, int height, int viewportW) {
+        String value = y;
+        if (WXAnimationBean.Style.TOP.equals(y)) {
+            value = ZERO;
+        } else if (WXAnimationBean.Style.BOTTOM.equals(y)) {
+            value = FULL;
+        } else if (WXAnimationBean.Style.CENTER.equals(y)) {
+            value = HALF;
+        }
+        return parsePercentOrPx(value, height,viewportW);
+    }
+
+    private static float parsePercentOrPx(String raw, int unit, int viewportW) {
+        final int precision = 1;
+        int suffix;
+        if ((suffix = raw.lastIndexOf(WXUtils.PERCENT)) != -1) {
+            return parsePercent(raw.substring(0, suffix), unit, precision);
+        } else if ((suffix = raw.lastIndexOf(PX)) != -1) {
+            return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw.substring(0, suffix), precision),viewportW);
+        }
+        return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw, precision),viewportW);
+    }
+
+    private static float parsePercent(String percent, int unit, int precision) {
+        return WXUtils.fastGetFloat(percent, precision) / 100 * unit;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/WXAnimationBean.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/WXAnimationBean.java
new file mode 100644
index 0000000..57a8bc7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/WXAnimationBean.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+import android.animation.PropertyValuesHolder;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Property;
+import android.view.View;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.Constants.Name;
+import org.apache.weex.utils.FunctionParser;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class WXAnimationBean {
+
+  public final static String LINEAR = "linear";
+  public final static String EASE_IN_OUT = "ease-in-out";
+  public final static String EASE_IN = "ease-in";
+  public final static String EASE_OUT = "ease-out";
+  public final static String CUBIC_BEZIER = "cubic-bezier";
+  public final static int NUM_CUBIC_PARAM = 4;
+  public long delay;
+  public long duration;
+  public String timingFunction;
+  public @Nullable Style styles;
+  public boolean needLayout;
+
+  public static class Style {
+
+    public final static String WX_TRANSLATE = "translate";
+    public final static String WX_TRANSLATE_X = "translateX";
+    public final static String WX_TRANSLATE_Y = "translateY";
+    public final static String WX_ROTATE = "rotate";
+    public final static String WX_SCALE_X = "scaleX";
+    public final static String WX_SCALE_Y = "scaleY";
+    public final static String WX_SCALE = "scale";
+    public final static String WX_ROTATE_X ="rotateX";
+    public final static String WX_ROTATE_Y ="rotateY";
+    public final static String BACKGROUND_COLOR = Constants.Name.BACKGROUND_COLOR;
+    public final static String WIDTH = Constants.Name.WIDTH;
+    public final static String HEIGHT = Constants.Name.HEIGHT;
+    public final static String TOP = "top";
+    public final static String BOTTOM = "bottom";
+    public final static String RIGHT = "right";
+    public final static String LEFT = "left";
+    public final static String CENTER = "center";
+    private static final String HALF = "50%";
+    private static final String FULL = "100%";
+    private static final String ZERO = "0%";
+    private static final String PX = "px";
+    private static final String DEG = "deg";
+    public static Map<String, List<Property<View,Float>>> wxToAndroidMap = new ArrayMap<>();
+    private static Map<Property<View, Float>, Float> defaultMap= new ArrayMap<>();
+
+
+    static {
+      wxToAndroidMap.put(WX_TRANSLATE, Arrays.asList
+              (View.TRANSLATION_X, View.TRANSLATION_Y));
+      wxToAndroidMap.put(WX_TRANSLATE_X, Collections.singletonList(View.TRANSLATION_X));
+      wxToAndroidMap.put(WX_TRANSLATE_Y, Collections.singletonList(View.TRANSLATION_Y));
+      wxToAndroidMap.put(WX_ROTATE, Collections.singletonList(View.ROTATION));
+      wxToAndroidMap.put(WX_ROTATE_X, Collections.singletonList(View.ROTATION_X));
+      wxToAndroidMap.put(WX_ROTATE_Y, Collections.singletonList(View.ROTATION_Y));
+      wxToAndroidMap.put(WX_SCALE, Arrays.asList(View.SCALE_X, View.SCALE_Y));
+      wxToAndroidMap.put(WX_SCALE_X, Collections.singletonList(View.SCALE_X));
+      wxToAndroidMap.put(WX_SCALE_Y, Collections.singletonList(View.SCALE_Y));
+      wxToAndroidMap.put(Name.PERSPECTIVE, Collections.singletonList(CameraDistanceProperty.getInstance()));
+      wxToAndroidMap = Collections.unmodifiableMap(wxToAndroidMap);
+      defaultMap.put(View.TRANSLATION_X, 0f);
+      defaultMap.put(View.TRANSLATION_Y, 0f);
+      defaultMap.put(View.SCALE_X, 1f);
+      defaultMap.put(View.SCALE_Y, 1f);
+      defaultMap.put(View.ROTATION, 0f);
+      defaultMap.put(View.ROTATION_X, 0f);
+      defaultMap.put(View.ROTATION_Y, 0f);
+    }
+
+    public String opacity;
+    public String backgroundColor;
+    public String width;
+    public String height;
+    public String transform;
+    public String transformOrigin;
+    private Map<Property<View, Float>, Float> transformMap = new LinkedHashMap<>();
+    private Pair<Float, Float> pivot;
+    private List<PropertyValuesHolder> holders=new LinkedList<>();
+    private float cameraDistance = Float.MAX_VALUE;
+
+
+    private static Pair<Float, Float> parsePivot(@Nullable String transformOrigin,
+                                                 int width, int height,int viewportW) {
+      if (!TextUtils.isEmpty(transformOrigin)) {
+        int firstSpace = transformOrigin.indexOf(FunctionParser.SPACE);
+        if (firstSpace != -1) {
+          int i = firstSpace;
+          for (; i < transformOrigin.length(); i++) {
+            if (transformOrigin.charAt(i) != FunctionParser.SPACE) {
+              break;
+            }
+          }
+          if (i < transformOrigin.length() && transformOrigin.charAt(i) != FunctionParser.SPACE) {
+            List<String> list = new ArrayList<>(2);
+            list.add(transformOrigin.substring(0, firstSpace).trim());
+            list.add(transformOrigin.substring(i, transformOrigin.length()).trim());
+            return parsePivot(list, width, height,viewportW);
+          }
+        }
+      }
+      return null;
+    }
+
+    private static Pair<Float, Float> parsePivot(@NonNull List<String> list, int width, int height,int viewportW) {
+      return new Pair<>(
+              parsePivotX(list.get(0), width,viewportW), parsePivotY(list.get(1), height,viewportW));
+    }
+
+    private static float parsePivotX(String x, int width,int viewportW) {
+      String value = x;
+      if (WXAnimationBean.Style.LEFT.equals(x)) {
+        value = ZERO;
+      } else if (WXAnimationBean.Style.RIGHT.equals(x)) {
+        value = FULL;
+      } else if (WXAnimationBean.Style.CENTER.equals(x)) {
+        value = HALF;
+      }
+      return parsePercentOrPx(value, width,viewportW);
+    }
+
+    private static float parsePivotY(String y, int height,int viewportW) {
+      String value = y;
+      if (WXAnimationBean.Style.TOP.equals(y)) {
+        value = ZERO;
+      } else if (WXAnimationBean.Style.BOTTOM.equals(y)) {
+        value = FULL;
+      } else if (WXAnimationBean.Style.CENTER.equals(y)) {
+        value = HALF;
+      }
+      return parsePercentOrPx(value, height,viewportW);
+    }
+
+    private static float parsePercentOrPx(String raw, int unit,int viewportW) {
+      final int precision = 1;
+      int suffix;
+      if ((suffix = raw.lastIndexOf(WXUtils.PERCENT)) != -1) {
+        return parsePercent(raw.substring(0, suffix), unit, precision);
+      } else if ((suffix = raw.lastIndexOf(PX)) != -1) {
+        return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw.substring(0, suffix), precision),viewportW);
+      }
+      return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw, precision),viewportW);
+    }
+
+    private static float parsePercent(String percent, int unit, int precision) {
+      return WXUtils.fastGetFloat(percent, precision) / 100 * unit;
+    }
+
+    private void resetToDefaultIfAbsent() {
+      for (Entry<Property<View, Float>, Float> entry : defaultMap.entrySet()) {
+        if (!transformMap.containsKey(entry.getKey())) {
+          transformMap.put(entry.getKey(), entry.getValue());
+        }
+      }
+    }
+
+    public @Nullable Pair<Float, Float> getPivot() {
+      return pivot;
+    }
+
+    public void init(@Nullable String transformOrigin,@Nullable String rawTransform,
+                     final int width, final int height,int viewportW, WXSDKInstance instance){
+      pivot = parsePivot(transformOrigin,width,height,viewportW);
+      transformMap.putAll(TransformParser.parseTransForm(instance.getInstanceId(), rawTransform, width,height,viewportW));
+      resetToDefaultIfAbsent();
+      if (transformMap.containsKey(CameraDistanceProperty.getInstance())) {
+        cameraDistance = transformMap.remove(CameraDistanceProperty.getInstance());
+      }
+      initHolders();
+    }
+
+    /**
+     * Use this method to init if you already have a list of Property
+     * The key is something like {@link View#TRANSLATION_X} and the value is a {@link Pair},
+     * of which the first is beginning value and the second is ending value.
+     * @param styles a list of Property
+     */
+    public void init(@NonNull Map<Property<View, Float>, Pair<Float, Float>> styles){
+      for(Entry<Property<View, Float>, Pair<Float, Float>> entry:styles.entrySet()){
+        holders.add(PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue().first, entry.getValue().second));
+      }
+    }
+
+    private void initHolders(){
+      for (Map.Entry<Property<View, Float>, Float> entry : transformMap.entrySet()) {
+        holders.add(PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue()));
+      }
+      if (!TextUtils.isEmpty(opacity)) {
+        holders.add(PropertyValuesHolder.ofFloat(View.ALPHA, WXUtils.fastGetFloat(opacity, 3)));
+      }
+    }
+
+    public List<PropertyValuesHolder> getHolders(){
+      return holders;
+    }
+
+    public float getCameraDistance(){
+      return cameraDistance;
+    }
+  }
+}
+
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/WXAnimationModule.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/WXAnimationModule.java
new file mode 100644
index 0000000..6874630
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/WXAnimationModule.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.ui.action.GraphicActionAnimation;
+import org.apache.weex.ui.component.WXComponent;
+
+public class WXAnimationModule extends WXModule {
+
+  @JSMethod
+  public void transition(@Nullable String ref, @Nullable String animation, @Nullable String callBack) {
+    if (!TextUtils.isEmpty(ref) && !TextUtils.isEmpty(animation) && mWXSDKInstance != null) {
+      //Due to animation module rely on the result of the css-layout and the batch mechanism of
+      //css-layout, the animation.transition must be delayed the batch time.
+      GraphicActionAnimation action = new GraphicActionAnimation(mWXSDKInstance, ref, animation, callBack);
+      WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+    }
+  }
+
+
+ 
+
+  //add by moxun on 12/26/2016
+  public static class AnimationHolder {
+
+    private WXAnimationBean wxAnimationBean;
+    private String callback;
+
+    public void execute(WXSDKInstance instance, WXComponent component) {
+      if (null != instance && null != component) {
+        GraphicActionAnimation action = new GraphicActionAnimation(instance, component.getRef(), wxAnimationBean, callback);
+        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
+      }
+    }
+
+    public AnimationHolder(WXAnimationBean wxAnimationBean, String callback) {
+      this.wxAnimationBean = wxAnimationBean;
+      this.callback = callback;
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/animation/WidthProperty.java b/android/sdk/src/main/java/org/apache/weex/ui/animation/WidthProperty.java
new file mode 100644
index 0000000..1e9bf82
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/animation/WidthProperty.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.animation;
+
+
+import android.view.ViewGroup.LayoutParams;
+
+public class WidthProperty extends LayoutParamsProperty {
+
+  @Override
+  protected Integer getProperty(LayoutParams layoutParams) {
+    return layoutParams.width;
+  }
+
+  @Override
+  protected void setProperty(LayoutParams layoutParams, Integer expected) {
+    layoutParams.width = expected;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/AbstractEditComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/component/AbstractEditComponent.java
new file mode 100644
index 0000000..3111b4f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/AbstractEditComponent.java
@@ -0,0 +1,1064 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.InputType;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.text.method.PasswordTransformationMethod;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.dom.CSSConstants;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import org.apache.weex.layout.MeasureMode;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.helper.SoftKeyboardDetector;
+import org.apache.weex.ui.component.helper.WXTimeInputHelper;
+import org.apache.weex.ui.view.WXEditText;
+import org.apache.weex.utils.TypefaceUtil;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import static org.apache.weex.dom.WXStyle.UNSET;
+
+/**
+ * Created by sospartan on 7/11/16.
+ */
+public abstract class AbstractEditComponent extends WXComponent<WXEditText> {
+
+  private final InputMethodManager mInputMethodManager;
+  private String mBeforeText = "";
+  private boolean mAutoFocus;
+  private String mType = "text";
+  private String mMax = null;
+  private String mMin = null;
+  private String mLastValue = "";
+  private int mEditorAction = EditorInfo.IME_ACTION_DONE;
+  private String mReturnKeyType = null;
+  private List<TextView.OnEditorActionListener> mEditorActionListeners;
+  private boolean mListeningKeyboard = false;
+  private SoftKeyboardDetector.Unregister mUnregister;
+  private boolean mIgnoreNextOnInputEvent = false;
+  private boolean mKeepSelectionIndex = false;
+  private TextFormatter mFormatter = null;
+  private List<TextWatcher> mTextChangedListeners;
+  private TextWatcher mTextChangedEventDispatcher;
+  private int mFormatRepeatCount = 0;
+  private static final int MAX_TEXT_FORMAT_REPEAT = 3;
+
+  private TextPaint mPaint = new TextPaint();
+  private int mLineHeight = UNSET;
+
+  public AbstractEditComponent(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+    super(instance, parent, isLazy, basicComponentData);
+    mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+    setContentBoxMeasurement(new ContentBoxMeasurement() {
+      /** uiThread = false **/
+      @Override
+      public void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode) {
+        if (CSSConstants.isUndefined(width) || widthMeasureMode == MeasureMode.UNSPECIFIED) {
+          width = 0;
+        }
+        mMeasureWidth = width;
+        mMeasureHeight = getMeasureHeight();
+      }
+
+      /** uiThread = false **/
+      @Override
+      public void layoutBefore() {
+        updateStyleAndAttrs();
+      }
+
+      /** uiThread = false **/
+      @Override
+      public void layoutAfter(float computedWidth, float computedHeight) {
+
+      }
+    });
+  }
+
+  @Override
+  protected void layoutDirectionDidChanged(boolean isRTL) {
+    String alignStr = (String) getStyles().get(Constants.Name.TEXT_ALIGN);
+    int textAlign = getTextAlign(alignStr);
+    if (textAlign <= 0) {
+      textAlign = Gravity.START;
+    }
+    if (getHostView() instanceof WXEditText) {
+      getHostView().setGravity(textAlign | getVerticalGravity());
+    }
+  }
+
+  protected final float getMeasuredLineHeight() {
+    return mLineHeight != UNSET && mLineHeight > 0 ? mLineHeight : mPaint.getFontMetrics(null);
+  }
+
+  protected float getMeasureHeight() {
+    return getMeasuredLineHeight();
+  }
+
+  protected void updateStyleAndAttrs() {
+    if (getStyles().size() > 0) {
+      int fontSize = UNSET, fontStyle = UNSET, fontWeight = UNSET;
+      String fontFamily = null;
+      if (getStyles().containsKey(Constants.Name.FONT_SIZE)) {
+        fontSize = WXStyle.getFontSize(getStyles(),getViewPortWidth());
+      }
+
+      if (getStyles().containsKey(Constants.Name.FONT_FAMILY)) {
+        fontFamily = WXStyle.getFontFamily(getStyles());
+      }
+
+      if (getStyles().containsKey(Constants.Name.FONT_STYLE)) {
+        fontStyle = WXStyle.getFontStyle(getStyles());
+      }
+
+      if (getStyles().containsKey(Constants.Name.FONT_WEIGHT)) {
+        fontWeight = WXStyle.getFontWeight(getStyles());
+      }
+
+      int lineHeight = WXStyle.getLineHeight(getStyles(),getViewPortWidth());
+      if (lineHeight != UNSET)
+        mLineHeight = lineHeight;
+
+      if (fontSize != UNSET)
+        mPaint.setTextSize(fontSize);
+
+      if (fontFamily != null) {
+        TypefaceUtil.applyFontStyle(mPaint, fontStyle, fontWeight, fontFamily);
+      }
+    }
+  }
+
+  @Override
+  protected WXEditText initComponentHostView(@NonNull Context context) {
+    final WXEditText inputView = new WXEditText(context);
+    appleStyleAfterCreated(inputView);
+    return inputView;
+  }
+
+  @Override
+  protected void onHostViewInitialized(WXEditText host) {
+    super.onHostViewInitialized(host);
+    addFocusChangeListener(new OnFocusChangeListener() {
+      @Override
+      public void onFocusChange(boolean hasFocus) {
+        if (!hasFocus) {
+          decideSoftKeyboard();
+        }
+        setPseudoClassStatus(Constants.PSEUDO.FOCUS,hasFocus);
+      }
+    });
+
+    addKeyboardListener(host);
+  }
+
+  @Override
+  protected boolean isConsumeTouch() {
+    //EditText always consume touch event except disabled.
+    return !isDisabled();
+  }
+
+  private OnClickListener mOnClickListener = new OnClickListener() {
+    @Override
+    public void onHostViewClick() {
+      switch (mType) {
+        case Constants.Value.DATE:
+          hideSoftKeyboard();
+          if (getParent() != null) {
+            getParent().interceptFocus();
+          }
+          WXTimeInputHelper.pickDate(mMax, mMin, AbstractEditComponent.this);
+          break;
+        case Constants.Value.TIME:
+          hideSoftKeyboard();
+          if (getParent() != null) {
+            getParent().interceptFocus();
+          }
+          WXTimeInputHelper.pickTime(AbstractEditComponent.this);
+          break;
+      }
+    }
+  };
+
+  private void applyOnClickListener() {
+    addClickListener(mOnClickListener);
+  }
+
+
+  protected int getVerticalGravity(){
+    return Gravity.CENTER_VERTICAL;
+  }
+
+  /**
+   * Process view after created.
+   *
+   * @param editText
+   */
+  protected void appleStyleAfterCreated(final WXEditText editText) {
+    String alignStr = (String) getStyles().get(Constants.Name.TEXT_ALIGN);
+    int textAlign = getTextAlign(alignStr);
+    if (textAlign <= 0) {
+      textAlign = Gravity.START;
+    }
+    editText.setGravity(textAlign | getVerticalGravity());
+    final int colorInt = WXResourceUtils.getColor("#999999");
+    if (colorInt != Integer.MIN_VALUE) {
+      editText.setHintTextColor(colorInt);
+    }
+
+    mTextChangedEventDispatcher = new TextWatcher() {
+      @Override
+      public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        if (mTextChangedListeners != null) {
+          for (TextWatcher watcher : mTextChangedListeners) {
+            watcher.beforeTextChanged(s, start, count, after);
+          }
+        }
+      }
+
+      @Override
+      public void onTextChanged(CharSequence s, int start, int before, int count) {
+        if (mFormatter != null) {
+          String raw = mFormatter.recover(s.toString());
+          String result = mFormatter.format(raw);
+          // prevent infinite loop caused by bad format and recover regexp
+          if (!result.equals(s.toString()) && mFormatRepeatCount < MAX_TEXT_FORMAT_REPEAT) {
+            mFormatRepeatCount = mFormatRepeatCount + 1;
+            int index = editText.getSelectionStart();
+            int cursorIndex = mFormatter.format(mFormatter.recover(s.subSequence(0, index).toString())).length();
+            editText.setText(result);
+            editText.setSelection(cursorIndex);
+            return;
+          }
+
+          mFormatRepeatCount = 0;
+        }
+
+        if (mTextChangedListeners != null) {
+          for (TextWatcher watcher : mTextChangedListeners) {
+            watcher.onTextChanged(s, start, before, count);
+          }
+        }
+      }
+
+      @Override
+      public void afterTextChanged(Editable s) {
+        if (mTextChangedListeners != null) {
+          for (TextWatcher watcher : mTextChangedListeners) {
+            watcher.afterTextChanged(s);
+          }
+        }
+      }
+    };
+    editText.addTextChangedListener(mTextChangedEventDispatcher);
+
+    editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, WXStyle.getFontSize(getStyles(), getInstance().getInstanceViewPortWidth()));
+  }
+
+
+  @Override
+  public void addEvent(final String type) {
+    super.addEvent(type);
+    if (getHostView() == null || TextUtils.isEmpty(type)) {
+      return;
+    }
+    final TextView text = getHostView();
+
+    if (type.equals(Constants.Event.CHANGE)) {
+      addFocusChangeListener(new OnFocusChangeListener() {
+        @Override
+        public void onFocusChange(boolean hasFocus) {
+          if (hasFocus) {
+            mLastValue = text.getText().toString();
+          } else {
+            CharSequence newValue = text.getText();
+            newValue = newValue == null ? "" : newValue;
+            if (!newValue.toString().equals(mLastValue)) {
+              fireEvent(Constants.Event.CHANGE, newValue.toString());
+              mLastValue = text.getText().toString();
+            }
+          }
+        }
+      });
+
+      addEditorActionListener(new TextView.OnEditorActionListener() {
+        @Override
+        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+          if (actionId == mEditorAction) {
+            CharSequence newValue = text.getText();
+            newValue = newValue == null ? "" : newValue;
+            if (!newValue.toString().equals(mLastValue)) {
+              fireEvent(Constants.Event.CHANGE, newValue.toString());
+              mLastValue = text.getText().toString();
+            }
+            if (getParent() != null) {
+              getParent().interceptFocus();
+            }
+            hideSoftKeyboard();
+            return true;
+          }
+          return false;
+        }
+      });
+    } else if (type.equals(Constants.Event.INPUT)) {
+      addTextChangedListener(new TextWatcher() {
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+          if (mIgnoreNextOnInputEvent) {
+            mIgnoreNextOnInputEvent = false;
+            mBeforeText = s.toString();
+            return;
+          }
+
+          if (mBeforeText.equals(s.toString())) {
+            return;
+          }
+
+          mBeforeText = s.toString();
+
+          fireEvent(Constants.Event.INPUT, s.toString());
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+
+        }
+      });
+    }
+
+    if (Constants.Event.RETURN.equals(type)) {
+      addEditorActionListener(new TextView.OnEditorActionListener() {
+        @Override
+        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+          if (actionId == mEditorAction) {
+            Map<String, Object> ret = new HashMap<>(2);
+            ret.put("returnKeyType", mReturnKeyType);
+            ret.put("value", v.getText().toString());
+            fireEvent(Constants.Event.RETURN, ret);
+            return true;
+          }
+          return false;
+        }
+      });
+    }
+
+    if (Constants.Event.KEYBOARD.equals(type)) {
+      mListeningKeyboard = true;
+    }
+  }
+
+  private void fireEvent(String event, String value) {
+    if (event != null) {
+      Map<String, Object> params = new HashMap<>(2);
+      params.put("value", value);
+      params.put("timeStamp", System.currentTimeMillis());
+
+      Map<String, Object> domChanges = new HashMap<>();
+      Map<String, Object> attrsChanges = new HashMap<>();
+      attrsChanges.put("value", value);
+      domChanges.put("attrs", attrsChanges);
+
+      WXSDKManager.getInstance().fireEvent(getInstanceId(), getRef(), event, params, domChanges);
+    }
+  }
+
+  public void performOnChange(String value) {
+    if (getEvents() != null) {
+      String event = getEvents().contains(Constants.Event.CHANGE) ? Constants.Event.CHANGE : null;
+      fireEvent(event, value);
+    }
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.DISABLED:
+        Boolean disabled = WXUtils.getBoolean(param, null);
+        if (disabled != null && mHost != null) {
+          if (disabled) {
+            mHost.setFocusable(false);
+            mHost.setFocusableInTouchMode(false);
+          } else {
+            mHost.setFocusableInTouchMode(true);
+            mHost.setFocusable(true);
+          }
+        }
+        return true;
+      case Constants.Name.PLACEHOLDER:
+        String placeholder = WXUtils.getString(param, null);
+        if (placeholder != null)
+          setPlaceholder(placeholder);
+        return true;
+      case Constants.Name.PLACEHOLDER_COLOR:
+        String placeholder_color = WXUtils.getString(param, null);
+        if (placeholder_color != null)
+          setPlaceholderColor(placeholder_color);
+        return true;
+      case Constants.Name.TYPE:
+        String input_type = WXUtils.getString(param, null);
+        if (input_type != null)
+          setType(input_type);
+        return true;
+      case Constants.Name.AUTOFOCUS:
+        Boolean result = WXUtils.getBoolean(param, null);
+        if (result != null)
+          setAutofocus(result);
+        return true;
+      case Constants.Name.COLOR:
+        String color = WXUtils.getString(param, null);
+        if (color != null)
+          setColor(color);
+        return true;
+      case Constants.Name.FONT_SIZE:
+        String fontsize = WXUtils.getString(param, null);
+        if (fontsize != null)
+          setFontSize(fontsize);
+        return true;
+      case Constants.Name.TEXT_ALIGN:
+        String text_align = WXUtils.getString(param, null);
+        if (text_align != null)
+          setTextAlign(text_align);
+        return true;
+      case Constants.Name.SINGLELINE:
+        Boolean singLineResult = WXUtils.getBoolean(param, null);
+        if (singLineResult != null)
+          setSingleLine(singLineResult);
+        return true;
+      case Constants.Name.LINES:
+        Integer lines = WXUtils.getInteger(param, null);
+        if (lines != null)
+          setLines(lines);
+        return true;
+      case Constants.Name.MAX_LENGTH:
+        Integer maxlength = WXUtils.getInteger(param, null);
+        if (maxlength != null)
+          setMaxLength(maxlength);
+        return true;
+      case Constants.Name.MAXLENGTH:
+        Integer maxLength = WXUtils.getInteger(param, null);
+        if (maxLength != null)
+          setMaxLength(maxLength);
+        return true;
+      case Constants.Name.MAX:
+        setMax(String.valueOf(param));
+        return true;
+      case Constants.Name.MIN:
+        setMin(String.valueOf(param));
+        return true;
+      case Constants.Name.RETURN_KEY_TYPE:
+        setReturnKeyType(String.valueOf(param));
+        return true;
+      case Constants.Name.KEEP_SELECTION_INDEX:
+        boolean keepIndex = WXUtils.getBoolean(param, false);
+        mKeepSelectionIndex = keepIndex;
+        return true;
+      case Constants.Name.ALLOW_COPY_PASTE:
+        boolean allowCopyPaste = WXUtils.getBoolean(param, true);
+        if (getHostView() != null) {
+          getHostView().setAllowCopyPaste(allowCopyPaste);
+        }
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @WXComponentProp(name = Constants.Name.RETURN_KEY_TYPE)
+  public void setReturnKeyType(String type) {
+    if (getHostView() == null) {
+      return;
+    }
+    mReturnKeyType = type;
+    switch (type) {
+      case ReturnTypes.DEFAULT:
+        mEditorAction = EditorInfo.IME_ACTION_UNSPECIFIED;
+        break;
+      case ReturnTypes.GO:
+        mEditorAction = EditorInfo.IME_ACTION_GO;
+        break;
+      case ReturnTypes.NEXT:
+        mEditorAction = EditorInfo.IME_ACTION_NEXT;
+        break;
+      case ReturnTypes.SEARCH:
+        mEditorAction = EditorInfo.IME_ACTION_SEARCH;
+        break;
+      case ReturnTypes.SEND:
+        mEditorAction = EditorInfo.IME_ACTION_SEND;
+        break;
+      case ReturnTypes.DONE:
+        mEditorAction = EditorInfo.IME_ACTION_DONE;
+        break;
+      default:
+        break;
+    }
+
+    //remove focus and hide keyboard first, the ImeOptions will take effect when show keyboard next time
+    blur();
+    getHostView().setImeOptions(mEditorAction);
+  }
+
+  @WXComponentProp(name = Constants.Name.PLACEHOLDER)
+  public void setPlaceholder(String placeholder) {
+    if (placeholder == null || getHostView() == null) {
+      return;
+    }
+    ((WXEditText) getHostView()).setHint(placeholder);
+  }
+
+  @WXComponentProp(name = Constants.Name.PLACEHOLDER_COLOR)
+  public void setPlaceholderColor(String color) {
+    if (getHostView() != null && !TextUtils.isEmpty(color)) {
+      int colorInt = WXResourceUtils.getColor(color);
+      if (colorInt != Integer.MIN_VALUE) {
+        ((WXEditText) getHostView()).setHintTextColor(colorInt);
+      }
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.TYPE)
+  public void setType(String type) {
+    Log.e("weex", "setType=" + type);
+    if (type == null || getHostView() == null) {
+      return;
+    }
+    mType = type;
+    ((EditText) getHostView()).setInputType(getInputType(mType));
+    switch (mType) {
+      case Constants.Value.DATE:
+      case Constants.Value.TIME:
+        applyOnClickListener();
+        break;
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.AUTOFOCUS)
+  public void setAutofocus(boolean autofocus) {
+    if (getHostView() == null) {
+      return;
+    }
+    mAutoFocus = autofocus;
+    EditText inputView = getHostView();
+    if (mAutoFocus) {
+      inputView.setFocusable(true);
+      inputView.requestFocus();
+      inputView.setFocusableInTouchMode(true);
+      showSoftKeyboard();
+    } else {
+      hideSoftKeyboard();
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.VALUE)
+  public void setValue(String value) {
+    WXEditText view;
+    if ((view = getHostView()) == null) {
+      return;
+    }
+    if (TextUtils.equals(view.getText(), value)) {
+      return;
+    }
+
+    mIgnoreNextOnInputEvent = true;
+    int oldIndex = view.getSelectionStart();
+    view.setText(value);
+    int index = mKeepSelectionIndex ? oldIndex : value.length();
+    view.setSelection(value == null ? 0 : index);
+  }
+
+  @WXComponentProp(name = Constants.Name.COLOR)
+  public void setColor(String color) {
+    if (getHostView() != null && !TextUtils.isEmpty(color)) {
+      int colorInt = WXResourceUtils.getColor(color);
+      if (colorInt != Integer.MIN_VALUE) {
+        getHostView().setTextColor(colorInt);
+      }
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.FONT_SIZE)
+  public void setFontSize(String fontSize) {
+    if (getHostView() != null && fontSize != null ) {
+      Map<String, Object> map = new HashMap<>(1);
+      map.put(Constants.Name.FONT_SIZE, fontSize);
+      getHostView().setTextSize(TypedValue.COMPLEX_UNIT_PX, WXStyle.getFontSize(map, getInstance().getInstanceViewPortWidth()));
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.TEXT_ALIGN)
+  public void setTextAlign(String textAlign) {
+    int align = getTextAlign(textAlign);
+    if (align > 0) {
+      getHostView().setGravity(align | getVerticalGravity());
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SINGLELINE)
+  public void setSingleLine(boolean singleLine) {
+    if (getHostView() == null) {
+      return;
+    }
+    getHostView().setSingleLine(singleLine);
+  }
+
+  @WXComponentProp(name = Constants.Name.LINES)
+  public void setLines(int lines) {
+    if (getHostView() == null) {
+      return;
+    }
+    getHostView().setLines(lines);
+  }
+
+  /**
+   * Compatible with both 'max-length' and 'maxlength'
+   * @param maxLength
+   */
+  @WXComponentProp(name = Constants.Name.MAX_LENGTH)
+  public void setMaxLength(int maxLength) {
+    if (getHostView() == null) {
+      return;
+    }
+    getHostView().setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
+  }
+
+  /**
+   * Compatible with both 'max-length' and 'maxlength'
+   * @param maxLength
+   */
+  @WXComponentProp(name = Constants.Name.MAXLENGTH)
+  @Deprecated
+  public void setMaxlength(int maxLength) {
+    setMaxLength(maxLength);
+  }
+
+  private int getInputType(String type) {
+    int inputType;
+    switch (type) {
+      case Constants.Value.TEXT:
+        inputType = InputType.TYPE_CLASS_TEXT;
+        break;
+      case Constants.Value.DATE:
+        inputType = InputType.TYPE_NULL;
+        getHostView().setFocusable(false);
+        break;
+      case Constants.Value.DATETIME:
+        inputType = InputType.TYPE_CLASS_DATETIME;
+        break;
+      case Constants.Value.EMAIL:
+        inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+        break;
+      case Constants.Value.PASSWORD:
+        inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+        if(getHostView() != null){
+            getHostView().setTransformationMethod(PasswordTransformationMethod.getInstance());
+        }
+        break;
+      case Constants.Value.TEL:
+        inputType = InputType.TYPE_CLASS_PHONE;
+        break;
+      case Constants.Value.TIME:
+        inputType = InputType.TYPE_NULL;
+        if(getHostView() != null){
+            getHostView().setFocusable(false);
+        }
+        break;
+      case Constants.Value.URL:
+        inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
+        break;
+      case Constants.Value.NUMBER:
+        inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL;
+        break;
+      default:
+        inputType = InputType.TYPE_CLASS_TEXT;
+    }
+    return inputType;
+  }
+
+  @WXComponentProp(name = Constants.Name.MAX)
+  public void setMax(String max) {
+    mMax = max;
+  }
+
+  @WXComponentProp(name = Constants.Name.MIN)
+  public void setMin(String min) {
+    mMin = min;
+  }
+
+  private boolean showSoftKeyboard() {
+    if (getHostView() == null) {
+      return false;
+    } else {
+      getHostView().postDelayed(WXThread.secure(new Runnable() {
+        @Override
+        public void run() {
+          if (getInstance() != null && getInstance().getApmForInstance() != null){
+            getInstance().getApmForInstance().forceStopRecordInteraction = true;
+          }
+          mInputMethodManager.showSoftInput(getHostView(), InputMethodManager.SHOW_IMPLICIT);
+        }
+      }), 100);
+    }
+    return true;
+  }
+
+  private void hideSoftKeyboard() {
+    if (getHostView() != null) {
+      getHostView().postDelayed(WXThread.secure(new Runnable() {
+        @Override
+        public void run() {
+          mInputMethodManager.hideSoftInputFromWindow(getHostView().getWindowToken(), 0);
+        }
+      }), 16);
+    }
+  }
+
+  private int getTextAlign(String textAlign) {
+    boolean isRTL = isLayoutRTL();
+    int align = isRTL ? Gravity.END : Gravity.START;
+    if (TextUtils.isEmpty(textAlign)) {
+      return align;
+    }
+
+    if (textAlign.equals(Constants.Value.LEFT)) {
+      align = Gravity.START;
+    } else if (textAlign.equals(Constants.Value.CENTER)) {
+      align = Gravity.CENTER;
+    } else if (textAlign.equals(Constants.Value.RIGHT)) {
+      align = Gravity.END;
+    }
+    return align;
+  }
+
+  @JSMethod
+  public void blur() {
+    WXEditText host = getHostView();
+    if (host != null && host.hasFocus()) {
+      if (getParent() != null) {
+        getParent().interceptFocus();
+      }
+      host.clearFocus();
+      hideSoftKeyboard();
+    }
+  }
+
+  @JSMethod
+  public void focus() {
+    WXEditText host = getHostView();
+    if (host != null && !host.hasFocus()) {
+      if (getParent() != null) {
+        getParent().ignoreFocus();
+      }
+      host.requestFocus();
+      host.setFocusable(true);
+      host.setFocusableInTouchMode(true);
+      showSoftKeyboard();
+    }
+  }
+
+  @Override
+  protected Object convertEmptyProperty(String propName, Object originalValue) {
+    switch (propName) {
+      case Constants.Name.FONT_SIZE:
+        return WXText.sDEFAULT_SIZE;
+      case Constants.Name.COLOR:
+        return "black";
+    }
+    return super.convertEmptyProperty(propName, originalValue);
+  }
+
+  private void decideSoftKeyboard() {
+    View hostView;
+    if ((hostView = getHostView()) != null) {
+      final Context context = getContext();
+      if (context != null && context instanceof Activity) {
+        hostView.postDelayed(WXThread.secure(new Runnable() {
+          @Override
+          public void run() {
+            View currentFocus = ((Activity) context).getCurrentFocus();
+            if (!(currentFocus instanceof EditText)) {
+              mInputMethodManager.hideSoftInputFromWindow(getHostView().getWindowToken(), 0);
+            }
+          }
+        }), 16);
+      }
+    }
+  }
+
+  @JSMethod
+  public void setSelectionRange(int selectionStart, int selectionEnd) {
+    EditText hostView;
+    if ((hostView = getHostView()) != null) {
+      int length = getHostView().length();
+      if (selectionStart > length || selectionEnd > length) {
+        return;
+      }
+      focus();
+      hostView.setSelection(selectionStart, selectionEnd);
+    }
+  }
+
+  @JSMethod
+  public void getSelectionRange(String callbackId) {
+    EditText hostView;
+    Map<String, Object> result = new HashMap<>(2);
+    if ((hostView = getHostView()) != null) {
+      int start = hostView.getSelectionStart();
+      int end = hostView.getSelectionEnd();
+
+      if (!hostView.hasFocus()) {
+        //The default behavior, same as iOS and web
+        start = 0;
+        end = 0;
+      }
+
+      result.put(Constants.Name.SELECTION_START, start);
+      result.put(Constants.Name.SELECTION_END, end);
+    }
+    WXBridgeManager.getInstance().callback(getInstanceId(), callbackId, result, false);
+  }
+
+  @JSMethod
+  public void setTextFormatter(JSONObject params) {
+    try {
+      String formatRule = params.getString("formatRule");
+      String formatReplace = params.getString("formatReplace");
+      String recoverRule = params.getString("recoverRule");
+      String recoverReplace = params.getString("recoverReplace");
+
+      PatternWrapper format = parseToPattern(formatRule, formatReplace);
+      PatternWrapper recover = parseToPattern(recoverRule, recoverReplace);
+
+      if (format != null && recover != null) {
+        mFormatter = new TextFormatter(format, recover);
+      }
+    } catch (Throwable t) {
+      t.printStackTrace();
+    }
+  }
+
+  protected final void addEditorActionListener(TextView.OnEditorActionListener listener) {
+    TextView view;
+    if (listener != null && (view = getHostView()) != null) {
+      if (mEditorActionListeners == null) {
+        mEditorActionListeners = new ArrayList<>();
+        view.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+          private boolean handled = true;
+
+          @Override
+          public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+            for (TextView.OnEditorActionListener l : mEditorActionListeners) {
+              if (l != null) {
+                handled = handled & l.onEditorAction(v, actionId, event);
+              }
+            }
+            return handled;
+          }
+        });
+      }
+      mEditorActionListeners.add(listener);
+    }
+  }
+
+  public final void addTextChangedListener(TextWatcher watcher) {
+    if (mTextChangedListeners == null) {
+      mTextChangedListeners = new ArrayList<>();
+    }
+    mTextChangedListeners.add(watcher);
+  }
+
+  private void addKeyboardListener(final WXEditText host) {
+    if (host == null) {
+      return;
+    }
+    final Context context = host.getContext();
+    if (context != null && context instanceof Activity) {
+      SoftKeyboardDetector.registerKeyboardEventListener((Activity) context, new SoftKeyboardDetector.OnKeyboardEventListener() {
+        @Override
+        public void onKeyboardEvent(boolean isShown) {
+          if (mListeningKeyboard) {
+            Map<String, Object> event = new HashMap<>(1);
+            event.put("isShow", isShown);
+            if (isShown) {
+              Rect r = new Rect();
+              ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
+              float keyboardSize = WXViewUtils.getWebPxByWidth(WXViewUtils.getScreenHeight(context) - (r.bottom - r.top),
+                      getInstance().getInstanceViewPortWidth());
+              event.put("keyboardSize", keyboardSize);
+            }
+            fireEvent(Constants.Event.KEYBOARD, event);
+          }
+          if (!isShown) {
+            blur();
+          }
+        }
+      });
+    }
+  }
+
+  @Override
+  public void destroy() {
+    super.destroy();
+    if (mUnregister != null) {
+      try {
+        mUnregister.execute();
+        mUnregister = null;
+      } catch (Throwable throwable) {
+        WXLogUtils.w("Unregister throw ", throwable);
+      }
+    }
+  }
+
+  private PatternWrapper parseToPattern(String jsPattern, String replace) {
+    if (jsPattern == null || replace == null) {
+      return null;
+    }
+
+    String checker = "/[\\S]+/[i]?[m]?[g]?";
+    if (!Pattern.compile(checker).matcher(jsPattern).matches()) {
+      WXLogUtils.w("WXInput", "Illegal js pattern syntax: " + jsPattern);
+      return null;
+    }
+
+    int flags = 0;
+    boolean global = false;
+    String flagsStr = jsPattern.substring(jsPattern.lastIndexOf("/") + 1);
+    String regExp = jsPattern.substring(jsPattern.indexOf("/") + 1, jsPattern.lastIndexOf("/"));
+
+    if (flagsStr.contains("i")) {
+      flags |= Pattern.CASE_INSENSITIVE;
+    }
+
+    if (flagsStr.contains("m")) {
+      flags |= Pattern.DOTALL;
+    }
+
+    if (flagsStr.contains("g")) {
+      global = true;
+    }
+
+    Pattern pattern = null;
+    try {
+      pattern = Pattern.compile(regExp, flags);
+    } catch (PatternSyntaxException e) {
+      WXLogUtils.w("WXInput", "Pattern syntax error: " + regExp);
+    }
+    if (pattern == null) {
+      return null;
+    }
+
+    PatternWrapper wrapper = new PatternWrapper();
+    wrapper.global = global;
+    wrapper.matcher = pattern;
+    wrapper.replace = replace;
+    return wrapper;
+  }
+
+  private interface ReturnTypes {
+    String DEFAULT = "default";
+    String GO = "go";
+    String NEXT = "next";
+    String SEARCH = "search";
+    String SEND = "send";
+    String DONE = "done";
+  }
+
+  private static class PatternWrapper {
+    private boolean global = false;
+    private Pattern matcher;
+    private String replace;
+  }
+
+  private static class TextFormatter {
+    private PatternWrapper format;
+    private PatternWrapper recover;
+
+    private TextFormatter(PatternWrapper format, PatternWrapper recover) {
+      this.format = format;
+      this.recover = recover;
+    }
+
+    private String format(String src) {
+      try {
+        if (format != null) {
+          if (format.global) {
+            return format.matcher.matcher(src).replaceAll(format.replace);
+          } else {
+            return format.matcher.matcher(src).replaceFirst(format.replace);
+          }
+        }
+      } catch (Throwable t) {
+        //maybe IndexOutOfBoundsException caused by illegal replace
+        WXLogUtils.w("WXInput", "[format] " + t.getMessage());
+      }
+      return src;
+    }
+
+    private String recover(String formatted) {
+      try {
+        if (recover != null) {
+          if (recover.global) {
+            return recover.matcher.matcher(formatted).replaceAll(recover.replace);
+          } else {
+            return recover.matcher.matcher(formatted).replaceFirst(recover.replace);
+          }
+        }
+      } catch (Throwable t) {
+        //same cause as format
+        WXLogUtils.w("WXInput", "[formatted] " + t.getMessage());
+      }
+      return formatted;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/AppearanceHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/AppearanceHelper.java
new file mode 100644
index 0000000..1668171
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/AppearanceHelper.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.graphics.Rect;
+import android.view.View;
+
+
+/**
+ * Created by sospartan on 8/19/16.
+ */
+public class AppearanceHelper {
+
+  private final WXComponent mAwareChild;
+
+  private boolean mAppearStatus = false;
+  private boolean[] mWatchFlags = {false, false};
+
+  public static final int APPEAR = 0;
+  public static final int DISAPPEAR = 1;
+
+  public static final int RESULT_APPEAR = 1;
+  public static final int RESULT_DISAPPEAR = -1;
+  public static final int RESULT_NO_CHANGE = 0;
+
+  private Rect mVisibleRect = new Rect();
+
+  private int mCellPositionInScrollable;
+
+  /**
+   * @param awareChild child to notify when appearance changed.
+   */
+  public AppearanceHelper(WXComponent awareChild) {
+    this(awareChild, 0);
+  }
+
+  public AppearanceHelper(WXComponent awareChild, int cellPositionInScrollable) {
+    mAwareChild = awareChild;
+    mCellPositionInScrollable = cellPositionInScrollable;
+  }
+
+  public void setCellPosition(int pos){
+    mCellPositionInScrollable = pos;
+  }
+
+  public int getCellPositionINScollable() {
+    return mCellPositionInScrollable;
+  }
+
+  /**
+   * @param event  {@link #APPEAR} and {@link #DISAPPEAR}
+   * @param enable
+   */
+  public void setWatchEvent(int event, boolean enable) {
+    mWatchFlags[event] = enable;
+  }
+
+  /**
+   * @return
+   */
+  public boolean isWatch() {
+    return mWatchFlags[APPEAR] || mWatchFlags[DISAPPEAR];
+  }
+
+
+  public WXComponent getAwareChild() {
+    return mAwareChild;
+  }
+
+  public boolean isAppear() {
+    return mAppearStatus;
+  }
+
+  public int setAppearStatus(boolean newIsAppear) {
+    if (mAppearStatus != newIsAppear) {
+      mAppearStatus = newIsAppear;
+      return newIsAppear ? RESULT_APPEAR : RESULT_DISAPPEAR;
+    }
+
+    return RESULT_NO_CHANGE;
+  }
+
+  public boolean isViewVisible(boolean isList) {
+    View view = mAwareChild.getHostView();
+    if(isList){
+      if(view.getVisibility() == View.VISIBLE){
+        if(view.getMeasuredHeight()  == 0){
+          return  true;
+        }
+      }
+    }
+    return view != null && view.getLocalVisibleRect(mVisibleRect);
+
+  }
+
+  public boolean isViewVisible(View view) {
+    if(view.getVisibility() == View.VISIBLE){
+      if(view.getMeasuredHeight()  == 0){
+        return  true;
+      }
+    }
+    return view != null && view.getLocalVisibleRect(mVisibleRect);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/NestedContainer.java b/android/sdk/src/main/java/org/apache/weex/ui/component/NestedContainer.java
new file mode 100644
index 0000000..32637b7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/NestedContainer.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.view.ViewGroup;
+import org.apache.weex.WXSDKInstance;
+
+/**
+ * Created by sospartan on 8/24/16.
+ */
+public interface NestedContainer {
+  void setOnNestEventListener(OnNestedInstanceEventListener listener);
+
+  ViewGroup getViewContainer();
+
+  void renderNewURL(String url);
+
+  void reload();
+
+  interface OnNestedInstanceEventListener {
+    void onException(NestedContainer comp, String errCode, String msg);
+
+    /**
+     *
+     * @param comp
+     * @param src
+     * @return true if keep load
+     */
+    boolean onPreCreate(NestedContainer comp, String src);
+
+    String transformUrl(String origin);
+
+    void onCreated(NestedContainer comp, WXSDKInstance nestedInstance);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/Scrollable.java b/android/sdk/src/main/java/org/apache/weex/ui/component/Scrollable.java
new file mode 100644
index 0000000..7a8299a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/Scrollable.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.view.ViewGroup;
+
+import java.util.Map;
+import org.apache.weex.common.Constants.Orientation;
+
+/**
+ * Created by sospartan on 7/5/16.
+ */
+public interface Scrollable {
+
+  void bindStickStyle(WXComponent component);
+
+  void unbindStickStyle(WXComponent component);
+
+  void bindAppearEvent(WXComponent component);
+
+  void bindDisappearEvent(WXComponent component);
+
+  void unbindAppearEvent(WXComponent component);
+
+  void unbindDisappearEvent(WXComponent component);
+
+  ViewGroup getView();
+
+  void scrollTo(WXComponent component, Map<String, Object> options);
+
+  String getRef();
+
+  int getScrollY();
+
+  int getScrollX();
+
+  /**
+   *
+   * @return {@link Orientation#HORIZONTAL} or {@link Orientation#VERTICAL}
+   */
+  int getOrientation();
+
+  boolean isScrollable();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/Textarea.java b/android/sdk/src/main/java/org/apache/weex/ui/component/Textarea.java
new file mode 100644
index 0000000..06b0da5
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/Textarea.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.text.TextUtils;
+import android.view.Gravity;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXEditText;
+import org.apache.weex.utils.WXUtils;
+
+/**
+ * Created by sospartan on 7/11/16.
+ */
+public class Textarea extends AbstractEditComponent {
+
+  public static final int DEFAULT_ROWS = 2;
+  private int mNumberOfLines = DEFAULT_ROWS;
+
+  public Textarea(
+      WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+    super(instance, parent, isLazy, basicComponentData);
+  }
+
+  @Override
+  protected void onHostViewInitialized(WXEditText host) {
+    host.setAllowDisableMovement(false);
+    super.onHostViewInitialized(host);
+  }
+
+  @Override
+  protected void appleStyleAfterCreated(WXEditText editText) {
+    super.appleStyleAfterCreated(editText);
+    String rowsStr = (String) getStyles().get(Constants.Name.ROWS);
+
+    int rows = DEFAULT_ROWS;
+    try{
+      if(!TextUtils.isEmpty(rowsStr)) {
+        rows = Integer.parseInt(rowsStr);
+      }
+    }catch (NumberFormatException e){
+      //ignore
+      e.printStackTrace();
+    }
+
+    editText.setLines(rows);
+    editText.setMinLines(rows);
+  }
+
+  @Override
+  protected int getVerticalGravity() {
+    return Gravity.TOP;
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.ROWS:
+        Integer rows = WXUtils.getInteger(param,null);
+        if (rows != null)
+          setRows(rows);
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @WXComponentProp(name = Constants.Name.ROWS)
+  public void setRows(int rows){
+    WXEditText text = getHostView();
+    if(text == null||rows <=0 ){
+      return;
+    }
+
+    text.setLines(rows);
+  }
+
+  @Override
+  protected float getMeasureHeight(){
+    return getMeasuredLineHeight() * mNumberOfLines;
+  }
+
+  @Override
+  protected void updateStyleAndAttrs() {
+    super.updateStyleAndAttrs();
+    Object raw = getAttrs().get(Constants.Name.ROWS);
+    if (raw == null) {
+      return;
+    } else if (raw instanceof String) {
+      String rowsStr = (String) raw;
+      try {
+        int lines = Integer.parseInt(rowsStr);
+        if (lines > 0) {
+          mNumberOfLines = lines;
+        }
+      } catch (NumberFormatException e) {
+        e.printStackTrace();
+      }
+    } else if (raw instanceof Integer) {
+      mNumberOfLines = (Integer) raw;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXA.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXA.java
new file mode 100644
index 0000000..f8d45bc
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXA.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXFrameLayout;
+import org.apache.weex.utils.ATagUtil;
+
+@Component(lazyload = false)
+public class WXA extends WXDiv {
+
+  @Deprecated
+  public WXA(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXA(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  @Override
+  protected void onHostViewInitialized(WXFrameLayout host) {
+    addClickListener(new OnClickListener() {
+      @Override
+      public void onHostViewClick() {
+        String href;
+        WXAttr attr = getAttrs();
+        if (attr !=null && (href = (String)attr.get("href")) != null) {
+          ATagUtil.onClick(null, getInstanceId(), href);
+        }
+      }
+    });
+    super.onHostViewInitialized(host);
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch(key){
+      case Constants.Name.HREF:
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXBaseRefresh.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXBaseRefresh.java
new file mode 100644
index 0000000..5ab59e6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXBaseRefresh.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXFrameLayout;
+
+/**
+ * div component
+ */
+@Component(lazyload = false)
+
+public class WXBaseRefresh extends WXVContainer<WXFrameLayout> {
+
+  private WXLoadingIndicator mLoadingIndicator;
+
+  public WXBaseRefresh(
+      WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
+    super(instance, parent, lazy, basicComponentData);
+  }
+
+  @Override
+  public void addChild(WXComponent child) {
+    super.addChild(child);
+    this.checkLoadingIndicator(child);
+  }
+
+  @Override
+  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
+    return new WXFrameLayout(context);
+  }
+
+  @Override
+  public void addChild(WXComponent child, int index) {
+    super.addChild(child, index);
+    this.checkLoadingIndicator(child);
+  }
+
+  private void checkLoadingIndicator(WXComponent child) {
+    if (child instanceof WXLoadingIndicator) {
+      mLoadingIndicator = (WXLoadingIndicator) child;
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXBasicComponentType.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXBasicComponentType.java
new file mode 100644
index 0000000..b6f7ccc
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXBasicComponentType.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+/**
+ * basic Component types
+ */
+public class WXBasicComponentType {
+
+  public static final String TEXT = "text";
+  public static final String IMAGE = "image";
+  public static final String IMG = "img";
+  public static final String CONTAINER = "container";
+  public static final String DIV = "div";
+  public static final String SCROLLER = "scroller";
+  public static final String SLIDER = "slider";
+  public static final String SLIDER_NEIGHBOR = "slider-neighbor";
+  public static final String LIST = "list";
+  public static final String RECYCLER = "recycler";
+  public static final String WATERFALL = "waterfall";
+  public static final String VLIST = "vlist";
+  public static final String HLIST = "hlist";
+  public static final String CELL = "cell";
+  public static final String HEADER = "header";
+  public static final String FOOTER = "footer";
+  public static final String INDICATOR = "indicator";
+  public static final String VIDEO = "video";
+  public static final String INPUT = "input";
+  public static final String TEXTAREA = "textarea";
+  public static final String SWITCH = "switch";
+  public static final String A = "a";
+  public static final String EMBED = "embed";
+  public static final String WEB = "web";
+  public static final String REFRESH = "refresh";
+  public static final String LOADING = "loading";
+  public static final String LOADING_INDICATOR = "loading-indicator";
+  public static final String CYCLE_SLIDER = "cycleslider";
+  public static final String RICHTEXT = "richtext";
+
+  public static final String RECYCLE_LIST = "recycle-list";
+  public static final String CELL_SLOT = "cell-slot";
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponent.java
new file mode 100644
index 0000000..9bdee05
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponent.java
@@ -0,0 +1,2470 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.RippleDrawable;
+import android.os.Build;
+import android.support.annotation.CallSuper;
+import android.support.annotation.CheckResult;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOverlay;
+import android.widget.FrameLayout;
+import com.alibaba.fastjson.JSONArray;
+import org.apache.weex.ComponentObserver;
+import org.apache.weex.IWXActivityStateListener;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXAccessibilityRoleAdapter;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.bridge.EventResult;
+import org.apache.weex.bridge.Invoker;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.IWXObject;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXPerformance;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.dom.CSSShorthand.CORNER;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.dom.transition.WXTransition;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import org.apache.weex.performance.WXAnalyzerDataTransfer;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.tracing.Stopwatch;
+import org.apache.weex.tracing.WXTracing;
+import org.apache.weex.ui.IFComponentHolder;
+import org.apache.weex.ui.WXRenderManager;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.action.GraphicActionAnimation;
+import org.apache.weex.ui.action.GraphicActionUpdateStyle;
+import org.apache.weex.ui.action.GraphicPosition;
+import org.apache.weex.ui.action.GraphicSize;
+import org.apache.weex.ui.animation.WXAnimationBean;
+import org.apache.weex.ui.component.basic.WXBasicComponent;
+import org.apache.weex.ui.component.binding.Statements;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
+import org.apache.weex.ui.component.pesudo.OnActivePseudoListner;
+import org.apache.weex.ui.component.pesudo.PesudoStatus;
+import org.apache.weex.ui.component.pesudo.TouchActivePseudoListener;
+import org.apache.weex.ui.flat.FlatComponent;
+import org.apache.weex.ui.flat.FlatGUIContext;
+import org.apache.weex.ui.flat.WidgetContainer;
+import org.apache.weex.ui.flat.widget.AndroidViewWidget;
+import org.apache.weex.ui.flat.widget.Widget;
+import org.apache.weex.ui.view.border.BorderDrawable;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.ui.view.gesture.WXGestureType;
+import org.apache.weex.utils.BoxShadowUtil;
+import org.apache.weex.utils.WXDataStructureUtil;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXReflectionUtils;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.apache.weex.common.Constants.Event;
+import org.apache.weex.tracing.WXTracing.TraceInfo;
+import org.apache.weex.ui.animation.WXAnimationModule.AnimationHolder;
+
+/**
+ * abstract component
+ */
+public abstract class WXComponent<T extends View> extends WXBasicComponent implements IWXObject,
+    IWXActivityStateListener, OnActivePseudoListner {
+
+  public static final String PROP_FIXED_SIZE = "fixedSize";
+  public static final String PROP_FS_MATCH_PARENT = "m";
+  public static final String PROP_FS_WRAP_CONTENT = "w";
+  public static final String TYPE = "type";
+  public static final String ROOT = "_root";
+
+  private int mFixedProp = 0;
+  /** package **/ T mHost;
+
+  private volatile WXVContainer mParent;
+  private WXSDKInstance mInstance;
+  private Context mContext;
+
+  private int mAbsoluteY = 0;
+  private int mAbsoluteX = 0;
+  private boolean isLastLayoutDirectionRTL = false;
+  @Nullable
+  private Set<String> mGestureType;
+
+  private BorderDrawable mBackgroundDrawable;
+  private Drawable mRippleBackground;
+  private int mPreRealWidth = 0;
+  private int mPreRealHeight = 0;
+  private int mPreRealLeft = 0;
+  private int mPreRealRight = 0;
+  private int mPreRealTop = 0;
+  private int mStickyOffset = 0;
+  protected WXGesture mGesture;
+  private IFComponentHolder mHolder;
+  private boolean isUsing = false;
+  private List<OnClickListener> mHostClickListeners;
+  private List<OnFocusChangeListener> mFocusChangeListeners;
+  private Set<String> mAppendEvents;
+  private AnimationHolder mAnimationHolder;
+  private PesudoStatus mPesudoStatus;
+  private boolean mIsDestroyed = false;
+  private boolean mIsDisabled = false;
+  private int mType = TYPE_COMMON;
+  private boolean mNeedLayoutOnAnimation = false;
+  private String mLastBoxShadowId;
+  public int mDeepInComponentTree = 0;
+  public boolean mIsAddElementToTree = false;
+  //for fix element case
+  public int interactionAbsoluteX=0,interactionAbsoluteY=0;
+  //for fix slider case :cssLeft is not real left base parent;
+  protected int mChildrensWidth = 0;
+  private boolean mHasAddFocusListener = false;
+
+  public TraceInfo mTraceInfo = new TraceInfo();
+
+  public static final int TYPE_COMMON = 0;
+  public static final int TYPE_VIRTUAL = 1;
+
+  private boolean waste = false;
+  public boolean isIgnoreInteraction = false;
+
+  protected ContentBoxMeasurement contentBoxMeasurement;
+  private WXTransition mTransition;
+  private GraphicSize mPseudoResetGraphicSize;
+  @Nullable
+  private ConcurrentLinkedQueue<Pair<String, Map<String, Object>>> animations;
+
+  @Deprecated
+  public WXComponent(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  @Deprecated
+  public WXComponent(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXComponent(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    this(instance, parent, TYPE_COMMON, basicComponentData);
+  }
+
+  public WXComponent(WXSDKInstance instance, WXVContainer parent, int type, BasicComponentData basicComponentData) {
+    super(basicComponentData);
+    mInstance = instance;
+    mContext = mInstance.getContext();
+    mParent = parent;
+    mType = type;
+
+    if (instance != null)
+      setViewPortWidth(instance.getInstanceViewPortWidth());
+
+    onCreate();
+    ComponentObserver observer;
+    if ((observer = getInstance().getComponentObserver()) != null) {
+      observer.onCreate(this);
+    }
+  }
+
+
+
+  @Override
+  protected final void bindComponent(WXComponent component) {
+    super.bindComponent(component);
+    if (getInstance() != null) {
+      setViewPortWidth(getInstance().getInstanceViewPortWidth());
+    }
+    mParent = component.getParent();
+    mType = component.getType();
+  }
+
+  protected final void setContentBoxMeasurement(final ContentBoxMeasurement contentBoxMeasurement) {
+    this.contentBoxMeasurement = contentBoxMeasurement;
+    mInstance.addContentBoxMeasurement(getRenderObjectPtr(), contentBoxMeasurement);
+    WXBridgeManager.getInstance().bindMeasurementToRenderObject(getRenderObjectPtr());
+  }
+
+
+  @SuppressLint("RtlHardcoded")
+  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
+      lp.setMargins(left, top, right, bottom);
+      if (lp instanceof FrameLayout.LayoutParams) {
+          FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
+          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
+      }
+  }
+
+  public void updateStyles(WXComponent component) {
+    if (component != null) {
+      updateProperties(component.getStyles());
+      applyBorder(component);
+    }
+  }
+
+  public void updateStyles(Map<String, Object> styles) {
+    if (styles != null) {
+      updateProperties(styles);
+      applyBorder(this);
+    }
+  }
+
+  public void updateAttrs(WXComponent component) {
+    if (component != null) {
+      updateProperties(component.getAttrs());
+    }
+  }
+
+  public void updateAttrs(Map<String, Object> attrs) {
+    if (attrs != null) {
+      updateProperties(attrs);
+    }
+  }
+
+  private void applyBorder(WXComponent component) {
+    CSSShorthand border = component.getBorder();
+    float left = border.get(CSSShorthand.EDGE.LEFT);
+    float top = border.get(CSSShorthand.EDGE.TOP);
+    float right = border.get(CSSShorthand.EDGE.RIGHT);
+    float bottom = border.get(CSSShorthand.EDGE.BOTTOM);
+
+    if (mHost == null) {
+      return;
+    }
+
+    setBorderWidth(Constants.Name.BORDER_LEFT_WIDTH, left);
+    setBorderWidth(Constants.Name.BORDER_TOP_WIDTH, top);
+    setBorderWidth(Constants.Name.BORDER_RIGHT_WIDTH, right);
+    setBorderWidth(Constants.Name.BORDER_BOTTOM_WIDTH, bottom);
+  }
+
+  public void setPadding(CSSShorthand padding, CSSShorthand border) {
+    int left = (int) (padding.get(CSSShorthand.EDGE.LEFT) + border.get(CSSShorthand.EDGE.LEFT));
+    int top = (int) (padding.get(CSSShorthand.EDGE.TOP) + border.get(CSSShorthand.EDGE.TOP));
+    int right = (int) (padding.get(CSSShorthand.EDGE.RIGHT) + border.get(CSSShorthand.EDGE.RIGHT));
+    int bottom = (int) (padding.get(CSSShorthand.EDGE.BOTTOM) + border.get(CSSShorthand.EDGE.BOTTOM));
+
+    if (this instanceof FlatComponent && !((FlatComponent) this).promoteToView(true)) {
+      ((FlatComponent) this).getOrCreateFlatWidget().setContentBox(left, top, right, bottom);
+    } else if (mHost != null) {
+      mHost.setPadding(left, top, right, bottom);
+    }
+  }
+
+
+  public void applyComponentEvents(){
+       applyEvents();
+  }
+
+  private void applyEvents() {
+    if (getEvents() == null || getEvents().isEmpty())
+      return;
+    WXEvent event = getEvents();
+    int size = event.size();
+    for (int i=0; i<size; i++) {
+      if(i >= event.size()){
+        break;
+      }
+      String type = event.get(i);
+      addEvent(type);
+    }
+    setActiveTouchListener();
+  }
+
+  /**
+   * Do not use this method to add event, this only apply event already add to DomObject.
+   *
+   * @param type
+   */
+  public void addEvent(final String type) {
+    if (mAppendEvents == null) {
+      mAppendEvents = new HashSet<>();
+    }
+    if (TextUtils.isEmpty(type) || mAppendEvents.contains(type)) {
+      return;
+    }
+    final View view = getRealView();
+
+    if (type.equals(Constants.Event.LAYEROVERFLOW))
+      addLayerOverFlowListener(getRef());
+
+    if (type.equals(Constants.Event.CLICK)) {
+      if (view == null) {
+        // wait next time to add.
+        return;
+      }
+      if(mClickEventListener == null){
+        mClickEventListener = new OnClickListenerImp();
+      }
+      addClickListener(mClickEventListener);
+    } else if ((type.equals(Constants.Event.FOCUS) || type.equals(Constants.Event.BLUR))) {
+      if (!mHasAddFocusListener){
+        mHasAddFocusListener = true;
+        addFocusChangeListener(new OnFocusChangeListener() {
+        @Override
+        public void onFocusChange(boolean hasFocus) {
+          Map<String, Object> params = new HashMap<>();
+          params.put("timeStamp", System.currentTimeMillis());
+          fireEvent(hasFocus ? Constants.Event.FOCUS : Constants.Event.BLUR, params);
+        }
+      });
+      }
+    } else if (needGestureDetector(type)) {
+      if (null == view) {
+        // wait next time to add.
+        return;
+      }
+      if (view instanceof WXGestureObservable) {
+        if (mGesture == null) {
+          mGesture = new WXGesture(this, mContext);
+          boolean isPreventMove = WXUtils.getBoolean(getAttrs().get(Constants.Name.PREVENT_MOVE_EVENT), false);
+          mGesture.setPreventMoveEvent(isPreventMove);
+        }
+        if (mGestureType == null) {
+          mGestureType = new HashSet<>();
+        }
+        mGestureType.add(type);
+        ((WXGestureObservable)view).registerGestureListener(mGesture);
+      } else {
+        WXLogUtils.e(view.getClass().getSimpleName() + " don't implement " +
+            "WXGestureObservable, so no gesture is supported.");
+      }
+    } else {
+      final Scrollable scroller = getParentScroller();
+      if (scroller == null) {
+        // wait next time to add.
+        return;
+      }
+      if (type.equals(Constants.Event.APPEAR)) {
+        scroller.bindAppearEvent(this);
+      } else if (type.equals(Constants.Event.DISAPPEAR)) {
+        scroller.bindDisappearEvent(this);
+      }
+    }
+    // Final add to mAppendEvents.
+    mAppendEvents.add(type);
+  }
+
+  protected void onCreate() {
+
+  }
+
+  public void bindHolder(IFComponentHolder holder) {
+    mHolder = holder;
+  }
+
+
+  public WXSDKInstance getInstance() {
+    return mInstance;
+  }
+
+  public Context getContext() {
+    return mContext;
+  }
+
+  /**
+   * Find component by component reference.
+   *
+   * @param ref
+   * @return
+   */
+  protected final WXComponent findComponent(String ref) {
+    if (mInstance != null && ref != null) {
+      return WXSDKManager.getInstance()
+              .getWXRenderManager()
+              .getWXComponent(mInstance.getInstanceId(), ref);
+    }
+    return null;
+  }
+
+  public String getAttrByKey(String key) {
+    return "default";
+  }
+
+  //Holding the animation bean when component is uninitialized
+  public void postAnimation(AnimationHolder holder) {
+    this.mAnimationHolder = holder;
+  }
+
+  //This method will be removed once flatGUI is completed.
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public boolean isFlatUIEnabled() {
+    return mParent != null && mParent.isFlatUIEnabled();
+  }
+
+  private class OnClickListenerImp implements OnClickListener{
+    @Override
+    public void onHostViewClick() {
+      Map<String, Object> param = WXDataStructureUtil.newHashMapWithExpectedSize(1);
+      Map<String, Object> position = WXDataStructureUtil.newHashMapWithExpectedSize(4);
+      int[] location = new int[2];
+      mHost.getLocationOnScreen(location);
+      position.put("x", WXViewUtils.getWebPxByWidth(location[0], mInstance.getInstanceViewPortWidth()));
+      position.put("y", WXViewUtils.getWebPxByWidth(location[1], mInstance.getInstanceViewPortWidth()));
+      position.put("width", WXViewUtils.getWebPxByWidth(getLayoutWidth(), mInstance.getInstanceViewPortWidth()));
+      position.put("height", WXViewUtils.getWebPxByWidth(getLayoutHeight(), mInstance.getInstanceViewPortWidth()));
+      param.put(Constants.Name.POSITION, position);
+      fireEvent(Constants.Event.CLICK, param);
+    }
+  };
+  private OnClickListenerImp mClickEventListener;
+
+  public String getInstanceId() {
+    return mInstance.getInstanceId();
+  }
+
+  public Rect getComponentSize() {
+    Rect size = new Rect();
+    if (mHost != null) {
+      int[] location = new int[2];
+      int[] anchor = new int[2];
+      mHost.getLocationOnScreen(location);
+      mInstance.getContainerView().getLocationOnScreen(anchor);
+
+      int left = location[0] - anchor[0];
+      int top = (location[1] - mStickyOffset) - anchor[1];
+      int width = (int) getLayoutWidth();
+      int height = (int) getLayoutHeight();
+      size.set(left, top, left + width, top + height);
+    }
+    return size;
+  }
+
+  public final void invoke(String method, JSONArray args) {
+    final Invoker invoker = mHolder.getMethodInvoker(method);
+    if (invoker != null) {
+      try {
+        getInstance()
+                .getNativeInvokeHelper()
+                .invoke(this, invoker, args);
+
+      } catch (Exception e) {
+        WXLogUtils.e("[WXComponent] updateProperties :" + "class:" + getClass() + "method:" + invoker.toString() + " function " + WXLogUtils.getStackTrace(e));
+      }
+    } else {
+      onInvokeUnknownMethod(method, args);
+    }
+  }
+
+  /**
+   * Will be invoked when request method not found.
+   * Subclass should override this method, If you return hard-code method list in {@link IFComponentHolder#getMethods()}
+   *
+   * @param method
+   * @param args
+   */
+  protected void onInvokeUnknownMethod(String method, JSONArray args) {
+
+  }
+
+  public interface OnClickListener {
+    void onHostViewClick();
+  }
+
+  public interface OnFocusChangeListener{
+    void onFocusChange(boolean hasFocus);
+  }
+
+  public final void fireEvent(String type){
+    fireEvent(type,null);
+  }
+
+  public final void fireEvent(String type, Map<String, Object> params){
+    if(WXUtils.getBoolean(getAttrs().get("fireEventSyn"), false)){
+      fireEventWait(type, params);
+    }else{
+      fireEvent(type, params,null, null);
+    }
+  }
+
+  public final EventResult fireEventWait(String type, Map<String, Object> params){
+    final CountDownLatch waitLatch = new CountDownLatch(1);
+    EventResult callback = new EventResult(){
+      @Override
+      public void onCallback(Object result) {
+        super.onCallback(result);
+        waitLatch.countDown();
+      }
+    };
+    try{
+      fireEvent(type, params, null, callback);
+      waitLatch.await(50, TimeUnit.MILLISECONDS);
+      return  callback;
+    }catch (Exception e){
+      if(WXEnvironment.isApkDebugable()){
+        WXLogUtils.e("fireEventWait", e);
+      }
+      return  callback;
+    }
+  }
+
+  protected final void fireEvent(String type, Map<String, Object> params,Map<String, Object> domChanges){
+    fireEvent(type, params, domChanges, null);
+  }
+
+
+  private final void fireEvent(String type, Map<String, Object> params,Map<String, Object> domChanges, EventResult callback){
+    if(mInstance != null) {
+      List<Object> eventArgsValues = null;
+      if(getEvents() != null && getEvents().getEventBindingArgsValues() != null){
+        eventArgsValues = getEvents().getEventBindingArgsValues().get(type);
+      }
+      if(params != null){
+        String componentId = Statements.getComponentId(this);
+        if(componentId != null) {
+          params.put("componentId", componentId);
+        }
+      }
+      mInstance.fireEvent(getRef(), type, params,domChanges, eventArgsValues, callback);
+    }
+  }
+
+  /**
+   * find certain class type parent
+   * */
+  public  Object findTypeParent(WXComponent component, Class type){
+    if(component.getClass() == type){
+      return component;
+    }
+    if(component.getParent() != null) {
+      findTypeParent(component.getParent(), type);
+    }
+    return  null;
+  }
+
+  /**
+   * The view is created as needed
+   * @return true for lazy
+   */
+  public boolean isLazy() {
+    if(mLazy){
+      return true;
+    }
+    return mParent != null && mParent.isLazy();
+  }
+
+  protected final void addFocusChangeListener(OnFocusChangeListener l){
+    View view;
+    if(l != null && (view = getRealView()) != null) {
+      if( mFocusChangeListeners == null){
+        mFocusChangeListeners = new ArrayList<>();
+        view.setFocusable(true);
+        view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+          @Override
+          public void onFocusChange(View v, boolean hasFocus) {
+            for (OnFocusChangeListener listener : mFocusChangeListeners){
+              if(listener != null){
+                listener.onFocusChange(hasFocus);
+              }
+            }
+          }
+        });
+      }
+      mFocusChangeListeners.add(l);
+    }
+  }
+
+  protected final void addClickListener(OnClickListener l){
+    View view;
+    if(l != null && (view = getRealView()) != null) {
+      if(mHostClickListeners == null){
+        mHostClickListeners = new ArrayList<>();
+        view.setOnClickListener(new View.OnClickListener() {
+          @Override
+          public void onClick(View v) {
+            if(mGesture != null && mGesture.isTouchEventConsumedByAdvancedGesture()){
+              //event is already consumed by gesture
+              return;
+            }
+            for (OnClickListener listener : mHostClickListeners){
+              if(listener != null) {
+                listener.onHostViewClick();
+              }
+            }
+          }
+        });
+      }
+      mHostClickListeners.add(l);
+
+    }
+  }
+
+  protected final void removeClickListener(OnClickListener l) {
+    mHostClickListeners.remove(l);
+  }
+
+  public void bindData(WXComponent component) {
+    if (!isLazy()) {
+      if (component == null) {
+        component = this;
+      }
+      bindComponent(component);
+      updateStyles(component);
+      updateAttrs(component);
+      updateExtra(component.getExtra());
+    }
+  }
+
+  public void applyLayoutAndEvent(WXComponent component) {
+    if (!isLazy()) {
+      if (component == null) {
+        component = this;
+      }
+      bindComponent(component);
+      setSafeLayout(component);
+      setPadding(component.getPadding(), component.getBorder());
+      applyEvents();
+    }
+  }
+
+  public void setDemission(GraphicSize size, GraphicPosition position) {
+    setLayoutPosition(position);
+    setLayoutSize(size);
+  }
+
+  public void updateDemission(float top, float bottom, float left, float right, float height, float width) {
+    getLayoutPosition().update(top, bottom, left, right);
+    getLayoutSize().update(width, height);
+  }
+
+
+  public void applyLayoutOnly(){
+    if(!isLazy()) {
+      setSafeLayout(this);
+      setPadding(this.getPadding(), this.getBorder());
+    }
+  }
+
+
+  public void refreshData(WXComponent component) {
+
+  }
+
+  @Deprecated
+  public void updateProperties(Map<String, Object> props) {
+    if (props == null || (mHost == null && !isVirtualComponent())) {
+      return;
+    }
+
+    for (Map.Entry<String, Object> entry : props.entrySet()) {
+      Object key_obj = entry.getKey();
+      String key = WXUtils.getString(key_obj, null);
+      if ((key != null) && !(key_obj instanceof String)) {
+        Map<String, String> map = new HashMap<>();
+        map.put("componentType", getComponentType());
+        map.put("actual key", key == null ? "" : key);
+        WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
+            WXErrorCode.WX_RENDER_ERR_COMPONENT_ATTR_KEY,
+            "WXComponent.updateProperties",
+            WXErrorCode.WX_RENDER_ERR_COMPONENT_ATTR_KEY.getErrorMsg(),
+            map);
+      }
+
+      Object param = entry.getValue();
+      String value = WXUtils.getString(param, null);
+
+      if (key == null) {
+        WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
+                WXErrorCode.WX_RENDER_ERR_NULL_KEY, "updateProperties",
+                WXErrorCode.WX_RENDER_ERR_NULL_KEY.getErrorMsg(), null);
+      } else {
+        if (TextUtils.isEmpty(value)) {
+          param = convertEmptyProperty(key, value);
+        }
+        if (!setProperty(key, param)) {
+          if (mHolder == null) {
+            return;
+          }
+          Invoker invoker = mHolder.getPropertyInvoker(key);
+          if (invoker != null) {
+            try {
+              Type[] paramClazzs = invoker.getParameterTypes();
+              if (paramClazzs.length != 1) {
+                WXLogUtils.e("[WXComponent] setX method only one parameter:" + invoker);
+                return;
+              }
+              param = WXReflectionUtils.parseArgument(paramClazzs[0], param);
+              invoker.invoke(this, param);
+            } catch (Exception e) {
+              WXLogUtils.e("[WXComponent] updateProperties :" + "class:" + getClass() + "method:" + invoker.toString() + " function " + WXLogUtils.getStackTrace(e));
+            }
+          }
+        }
+      }
+    }
+    readyToRender();
+    if (this instanceof FlatComponent && mBackgroundDrawable != null) {
+      FlatComponent flatComponent = (FlatComponent) this;
+      if (!flatComponent.promoteToView(true) && !(flatComponent
+              .getOrCreateFlatWidget() instanceof AndroidViewWidget)) {
+        flatComponent.getOrCreateFlatWidget().setBackgroundAndBorder(mBackgroundDrawable);
+      }
+    }
+  }
+
+  /**
+   * Apply styles and attributes.
+   *
+   * @param key   name of argument
+   * @param param value of argument
+   * @return true means that the property is consumed
+   */
+  protected boolean setProperty(String key, Object param) {
+    if(key == null){
+      return true;
+    }
+    switch (key) {
+      case Constants.Name.PREVENT_MOVE_EVENT:
+        if (mGesture != null) {
+          mGesture.setPreventMoveEvent(WXUtils.getBoolean(param, false));
+        }
+        return true;
+      case Constants.Name.DISABLED:
+        Boolean disabled = WXUtils.getBoolean(param, null);
+        if (disabled != null) {
+          setDisabled(disabled);
+          setPseudoClassStatus(Constants.PSEUDO.DISABLED, disabled);
+        }
+        return true;
+      case Constants.Name.POSITION:
+        String position = WXUtils.getString(param, null);
+        if (position != null)
+          setSticky(position);
+        return true;
+      case Constants.Name.BACKGROUND_COLOR:
+        String bgColor = WXUtils.getString(param, null);
+        if (bgColor != null)
+          setBackgroundColor(bgColor);
+        return true;
+      case Constants.Name.BACKGROUND_IMAGE:
+        String bgImage = WXUtils.getString(param, null);
+        if (bgImage != null && mHost != null) {
+          setBackgroundImage(bgImage);
+        }
+        return true;
+      case Constants.Name.OPACITY:
+        Float opacity = WXUtils.getFloat(param, null);
+        if (opacity != null)
+          setOpacity(opacity);
+        return true;
+      case Constants.Name.BORDER_RADIUS:
+      case Constants.Name.BORDER_TOP_LEFT_RADIUS:
+      case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
+      case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
+      case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
+        Float radius = WXUtils.getFloat(param, null);
+        if (radius != null)
+          setBorderRadius(key, radius);
+        return true;
+      case Constants.Name.BORDER_STYLE:
+      case Constants.Name.BORDER_RIGHT_STYLE:
+      case Constants.Name.BORDER_BOTTOM_STYLE:
+      case Constants.Name.BORDER_LEFT_STYLE:
+      case Constants.Name.BORDER_TOP_STYLE:
+        String border_style = WXUtils.getString(param, null);
+        if (border_style != null)
+          setBorderStyle(key, border_style);
+        return true;
+      case Constants.Name.BORDER_COLOR:
+      case Constants.Name.BORDER_TOP_COLOR:
+      case Constants.Name.BORDER_RIGHT_COLOR:
+      case Constants.Name.BORDER_BOTTOM_COLOR:
+      case Constants.Name.BORDER_LEFT_COLOR:
+        String border_color = WXUtils.getString(param, null);
+        if (border_color != null)
+          setBorderColor(key, border_color);
+        return true;
+      case Constants.Name.VISIBILITY:
+        String visibility = WXUtils.getString(param, null);
+        if (visibility != null)
+          setVisibility(visibility);
+        return true;
+      case Constants.Name.ELEVATION:
+        if (param != null) {
+          updateElevation();
+        }
+        return true;
+      case PROP_FIXED_SIZE:
+        String fixedSize = WXUtils.getString(param, PROP_FS_MATCH_PARENT);
+        setFixedSize(fixedSize);
+        return true;
+      case Constants.Name.ARIA_LABEL:
+        String label = WXUtils.getString(param, "");
+        setAriaLabel(label);
+        return true;
+      case Constants.Name.ARIA_HIDDEN:
+        boolean isHidden = WXUtils.getBoolean(param, false);
+        setAriaHidden(isHidden);
+        return true;
+      case Constants.Name.WIDTH:
+      case Constants.Name.MIN_WIDTH:
+      case Constants.Name.MAX_WIDTH:
+      case Constants.Name.HEIGHT:
+      case Constants.Name.MIN_HEIGHT:
+      case Constants.Name.MAX_HEIGHT:
+      case Constants.Name.ALIGN_ITEMS:
+      case Constants.Name.ALIGN_SELF:
+      case Constants.Name.FLEX:
+      case Constants.Name.FLEX_DIRECTION:
+      case Constants.Name.JUSTIFY_CONTENT:
+      case Constants.Name.FLEX_WRAP:
+      case Constants.Name.MARGIN:
+      case Constants.Name.MARGIN_TOP:
+      case Constants.Name.MARGIN_LEFT:
+      case Constants.Name.MARGIN_RIGHT:
+      case Constants.Name.MARGIN_BOTTOM:
+      case Constants.Name.PADDING:
+      case Constants.Name.PADDING_TOP:
+      case Constants.Name.PADDING_LEFT:
+      case Constants.Name.PADDING_RIGHT:
+      case Constants.Name.PADDING_BOTTOM:
+      case Constants.Name.BORDER_WIDTH:
+      case Constants.Name.BORDER_TOP_WIDTH:
+      case Constants.Name.BORDER_RIGHT_WIDTH:
+      case Constants.Name.BORDER_BOTTOM_WIDTH:
+      case Constants.Name.BORDER_LEFT_WIDTH:
+      case Constants.Name.LEFT:
+      case Constants.Name.TOP:
+      case Constants.Name.RIGHT:
+      case Constants.Name.BOTTOM:
+        return true;
+      case Constants.Name.BOX_SHADOW:
+        try {
+          updateBoxShadow();
+        } catch (Throwable t) {
+          t.printStackTrace();
+        }
+        return true;
+      case Constants.Name.ROLE:
+        setRole(WXUtils.getString(param, ""));
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  protected BorderDrawable getOrCreateBorder() {
+    if (mBackgroundDrawable == null) {
+      mBackgroundDrawable = new BorderDrawable();
+      if (mHost != null) {
+        WXViewUtils.setBackGround(mHost, null, this);
+        if (mRippleBackground == null) {
+          WXViewUtils.setBackGround(mHost, mBackgroundDrawable, this);
+        } else {
+          //TODO Not strictly clip according to background-clip:border-box
+          WXViewUtils.setBackGround(mHost, new LayerDrawable(new Drawable[]{
+                  mRippleBackground, mBackgroundDrawable}), this);
+        }
+      }
+    }
+    return mBackgroundDrawable;
+  }
+
+  /**
+   * layout view
+   */
+  public void setSafeLayout(WXComponent component) {
+    if (TextUtils.isEmpty(component.getComponentType())
+            || TextUtils.isEmpty(component.getRef()) || component.getLayoutPosition() == null
+            || component.getLayoutSize() == null) {
+      return;
+    }
+    setLayout(component);
+  }
+
+  /**
+   * layout view
+   */
+  public void setLayout(WXComponent component) {
+    setLayoutSize(component.getLayoutSize());
+    setLayoutPosition(component.getLayoutPosition());
+    setPaddings(component.getPadding());
+    setMargins(component.getMargin());
+    setBorders(component.getBorder());
+
+    boolean isRTL = component.isLayoutRTL();
+    setIsLayoutRTL(isRTL);
+    if (isRTL != component.isLastLayoutDirectionRTL) {
+      component.isLastLayoutDirectionRTL = isRTL;
+      layoutDirectionDidChanged(isRTL);
+    }
+
+    parseAnimation();
+
+    boolean nullParent = mParent == null;//parent is nullable
+
+    //offset by sibling
+    int siblingOffset = nullParent ? 0 : mParent.getChildrenLayoutTopOffset();
+
+    CSSShorthand parentPadding = (nullParent ? new CSSShorthand() : mParent.getPadding());
+    CSSShorthand parentBorder = (nullParent ? new CSSShorthand() : mParent.getBorder());
+
+    int realWidth = (int) getLayoutSize().getWidth();
+    int realHeight = (int) getLayoutSize().getHeight();
+
+    int realLeft = 0;
+    int realTop = 0;
+    int realRight = 0;
+
+    if (isFixed()) {
+      realLeft = (int) (getLayoutPosition().getLeft() - getInstance().getRenderContainerPaddingLeft());
+      realTop = (int) (getLayoutPosition().getTop() - getInstance().getRenderContainerPaddingTop()) + siblingOffset;
+    } else {
+      realLeft = (int) (getLayoutPosition().getLeft() -
+              parentPadding.get(CSSShorthand.EDGE.LEFT) - parentBorder.get(CSSShorthand.EDGE.LEFT));
+      realTop = (int) (getLayoutPosition().getTop() -
+              parentPadding.get(CSSShorthand.EDGE.TOP) - parentBorder.get(CSSShorthand.EDGE.TOP)) + siblingOffset;
+    }
+
+    realRight = (int) getMargin().get(CSSShorthand.EDGE.RIGHT);
+    int realBottom = (int) getMargin().get(CSSShorthand.EDGE.BOTTOM);
+
+    Point rawOffset = new Point(
+            (int) getLayoutPosition().getLeft(),
+            (int) getLayoutPosition().getTop());
+
+    if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft && mPreRealRight == realRight && mPreRealTop == realTop) {
+      return;
+    }
+
+    if (this instanceof WXCell && realHeight >= WXPerformance.VIEW_LIMIT_HEIGHT && realWidth>=WXPerformance.VIEW_LIMIT_WIDTH){
+      mInstance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_EXCEED_NUM,1);
+      mInstance.getWXPerformance().cellExceedNum++;
+      if (WXAnalyzerDataTransfer.isOpenPerformance){
+        WXAnalyzerDataTransfer.transferPerformance(getInstanceId(),"details",WXInstanceApm.KEY_PAGE_STATS_CELL_EXCEED_NUM,
+            String.format(Locale.ROOT, "cell:ref:%s,[w:%d,h:%d],attrs:%s,styles:%s",getRef(),realWidth,realHeight,getAttrs(),getStyles())
+        );
+      }
+
+    }
+
+    mAbsoluteY = (int) (nullParent ? 0 : mParent.getAbsoluteY() + getCSSLayoutTop());
+    mAbsoluteX = (int) (nullParent ? 0 : mParent.getAbsoluteX() + getCSSLayoutLeft());
+
+    if (mHost == null) {
+      return;
+    }
+
+    //calculate first screen time
+    if (!(mHost instanceof ViewGroup) && mAbsoluteY + realHeight > mInstance.getWeexHeight() + 1) {
+      if (!mInstance.mEnd){
+        mInstance.onOldFsRenderTimeLogic();
+      }
+      if (!mInstance.isNewFsEnd){
+        mInstance.isNewFsEnd = true;
+        mInstance.getApmForInstance().arriveNewFsRenderTime();
+      }
+    }
+
+    MeasureOutput measureOutput = measure(realWidth, realHeight);
+    realWidth = measureOutput.width;
+    realHeight = measureOutput.height;
+
+    setComponentLayoutParams(realWidth, realHeight, realLeft, realTop, realRight, realBottom, rawOffset);
+  }
+
+  private void setComponentLayoutParams(int realWidth, int realHeight, int realLeft, int realTop,
+                                        int realRight, int realBottom, Point rawOffset) {
+    if(getInstance() == null || getInstance().isDestroy()){
+      return;
+    }
+
+    FlatGUIContext UIImp = getInstance().getFlatUIContext();
+    WidgetContainer ancestor;
+    Widget widget;
+    if (UIImp != null && (ancestor = UIImp.getFlatComponentAncestor(this)) != null) {
+      if (this instanceof FlatComponent && !((FlatComponent) this).promoteToView(true)) {
+        widget = ((FlatComponent) this).getOrCreateFlatWidget();
+      } else {
+        widget = UIImp.getAndroidViewWidget(this);
+      }
+      setWidgetParams(widget, UIImp, rawOffset, realWidth, realHeight, realLeft, realRight, realTop,
+              realBottom);
+    } else if (mHost != null) {
+      // clear box shadow before host's size changed
+      clearBoxShadow();
+      if (isFixed()) {
+        setFixedHostLayoutParams(mHost, realWidth, realHeight, realLeft, realRight, realTop,
+                realBottom);
+      } else {
+        setHostLayoutParams(mHost, realWidth, realHeight, realLeft, realRight, realTop, realBottom);
+      }
+      recordInteraction(realWidth,realHeight);
+      mPreRealWidth = realWidth;
+      mPreRealHeight = realHeight;
+      mPreRealLeft = realLeft;
+      mPreRealRight = realRight;
+      mPreRealTop = realTop;
+      onFinishLayout();
+      // restore box shadow
+      updateBoxShadow();
+    }
+  }
+
+  /**
+   * layout direction is changed
+   * basic class is a empty implementation
+   * subclass can override this method do some RTL necessary things
+   * such as WXText
+   */
+  protected void layoutDirectionDidChanged(boolean isRTL) {
+
+  }
+
+  private void recordInteraction(int realWidth,int realHeight){
+    if (!mIsAddElementToTree){
+      return;
+    }
+    mIsAddElementToTree = false;
+    if (null == mParent){
+      interactionAbsoluteX = 0;
+      interactionAbsoluteY = 0;
+    }else {
+      float cssTop = getCSSLayoutTop();
+      float cssLeft = getCSSLayoutLeft();
+      interactionAbsoluteX = (int)(this.isFixed() ? cssLeft : mParent.interactionAbsoluteX + mParent.mChildrensWidth + cssLeft);
+      interactionAbsoluteY = (int)(this.isFixed() ? cssTop  : mParent.interactionAbsoluteY + cssTop);
+      //fix for slider impl ,and interactionTime calculate if component is out screen
+      if (WXBasicComponentType.SLIDER.equalsIgnoreCase(mParent.getComponentType()) || WXBasicComponentType.CYCLE_SLIDER.equalsIgnoreCase(mParent.getComponentType())){
+        if (!WXBasicComponentType.INDICATOR.equalsIgnoreCase(getComponentType())){
+          mParent.mChildrensWidth += (int)(realWidth + cssLeft);
+        }
+      }
+    }
+
+    if (null == getInstance().getApmForInstance().instanceRect){
+      getInstance().getApmForInstance().instanceRect = new Rect();
+    }
+    Rect instanceRect = getInstance().getApmForInstance().instanceRect;
+    instanceRect.set(0,0,mInstance.getWeexWidth(),mInstance.getWeexHeight());
+    boolean inScreen =
+          instanceRect.contains(interactionAbsoluteX,interactionAbsoluteY) //leftTop
+              || instanceRect.contains(interactionAbsoluteX+realWidth,interactionAbsoluteY)//rightTop
+              || instanceRect.contains(interactionAbsoluteX,interactionAbsoluteY+realHeight)//leftBottom
+              || instanceRect.contains(interactionAbsoluteX+realWidth,interactionAbsoluteY+realHeight);//rightBottom
+    mInstance.onChangeElement(this,!inScreen);
+  }
+
+  private void setWidgetParams(Widget widget, FlatGUIContext UIImp, Point rawoffset,
+                               int width, int height, int left, int right, int top, int bottom) {
+    Point childOffset = new Point();
+    if (mParent != null) {
+      if (mParent instanceof FlatComponent &&
+              UIImp.getFlatComponentAncestor(mParent) != null &&
+              UIImp.getAndroidViewWidget(mParent) == null) {
+        childOffset.set(rawoffset.x, rawoffset.y);
+      }
+      else{
+        childOffset.set(left, top);
+      }
+
+      if (mParent instanceof FlatComponent &&
+              UIImp.getFlatComponentAncestor(mParent) != null &&
+              UIImp.getAndroidViewWidget(mParent) == null) {
+        Point parentLayoutOffset = ((FlatComponent) mParent).getOrCreateFlatWidget().getLocInFlatContainer();
+        childOffset.offset(parentLayoutOffset.x, parentLayoutOffset.y);
+      }
+      ViewGroup.LayoutParams lp = mParent
+              .getChildLayoutParams(this, mHost, width, height, left, right, top, bottom);
+      if (lp instanceof ViewGroup.MarginLayoutParams) {
+        width = lp.width;
+        height = lp.height;
+        left = ((ViewGroup.MarginLayoutParams) lp).leftMargin;
+        right = ((ViewGroup.MarginLayoutParams) lp).rightMargin;
+        top = ((ViewGroup.MarginLayoutParams) lp).topMargin;
+        bottom = ((ViewGroup.MarginLayoutParams) lp).bottomMargin;
+      }
+    }
+    widget.setLayout(width, height, left, right, top, bottom, childOffset);
+
+    if (widget instanceof AndroidViewWidget && ((AndroidViewWidget) widget).getView()!=null) {
+      //TODO generic method if ever possible
+      setHostLayoutParams((T) ((AndroidViewWidget) widget).getView(),
+              width, height, childOffset.x, right, childOffset.y, bottom);
+    }
+  }
+
+  public int getLayoutTopOffsetForSibling() {
+    return 0;
+  }
+
+  protected void setHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom) {
+    ViewGroup.LayoutParams lp;
+    if (mParent == null) {
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
+        this.setMarginsSupportRTL(params, left, top, right, bottom);
+        lp = params;
+    } else {
+        lp = mParent.getChildLayoutParams(this, host, width, height, left, right, top, bottom);
+    }
+    if (lp != null) {
+        host.setLayoutParams(lp);
+    }
+  }
+
+  private void setFixedHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom){
+    FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+    params.width = width;
+    params.height = height;
+
+    this.setMarginsSupportRTL(params, left, top, right, bottom);
+
+    host.setLayoutParams(params);
+    mInstance.moveFixedView(host);
+
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout :" + left + " " + top + " " + width + " " + height);
+      WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout Left:" + getStyles().getLeft() + " " + (int) getStyles().getTop());
+    }
+  }
+
+  protected void updateBoxShadow() {
+    if (!BoxShadowUtil.isBoxShadowEnabled()) {
+//      WXLogUtils.w("BoxShadow", "box-shadow disabled");
+      return;
+    }
+
+    if (getStyles() != null) {
+      Object boxShadow = getStyles().get(Constants.Name.BOX_SHADOW);
+      Object shadowQuality = getAttrs().get(Constants.Name.SHADOW_QUALITY);
+      if (boxShadow == null) {
+        return;
+      }
+
+      View target = mHost;
+      if (this instanceof WXVContainer) {
+        target = ((WXVContainer) this).getBoxShadowHost(false);
+      }
+
+      if (target == null) {
+        return;
+      }
+
+      float quality = WXUtils.getFloat(shadowQuality, 0.5f);
+      int viewPort = getInstance().getInstanceViewPortWidth();
+      String token = new StringBuilder(boxShadow.toString()).append(" / [")
+              .append(target.getMeasuredWidth()).append(",")
+              .append(target.getMeasuredHeight()).append("] / ")
+              .append(quality).toString();
+
+      if (mLastBoxShadowId != null && mLastBoxShadowId.equals(token)) {
+        WXLogUtils.d("BoxShadow", "box-shadow style was not modified. " + token);
+        return;
+      }
+
+      float[] radii = new float[]{0, 0, 0, 0, 0, 0, 0, 0};
+      WXStyle style = getStyles();
+      if (style != null) {
+        float tl = WXUtils.getFloat(style.get(Constants.Name.BORDER_TOP_LEFT_RADIUS), 0f);
+        radii[0] = tl;
+        radii[1] = tl;
+
+        float tr = WXUtils.getFloat(style.get(Constants.Name.BORDER_TOP_RIGHT_RADIUS), 0f);
+        radii[2] = tr;
+        radii[3] = tr;
+
+        float br = WXUtils.getFloat(style.get(Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS), 0f);
+        radii[4] = br;
+        radii[5] = br;
+
+        float bl = WXUtils.getFloat(style.get(Constants.Name.BORDER_BOTTOM_LEFT_RADIUS), 0f);
+        radii[6] = bl;
+        radii[7] = bl;
+
+        if (style.containsKey(Constants.Name.BORDER_RADIUS)) {
+          float radius = WXUtils.getFloat(style.get(Constants.Name.BORDER_RADIUS), 0f);
+          for (int i = 0; i < radii.length; i++) {
+            radii[i] = radius;
+          }
+        }
+      }
+
+      BoxShadowUtil.setBoxShadow(target, boxShadow.toString(), radii, viewPort, quality);
+      mLastBoxShadowId = token;
+    } else {
+      WXLogUtils.w("Can not resolve styles");
+    }
+  }
+
+  protected void clearBoxShadow() {
+    if (!BoxShadowUtil.isBoxShadowEnabled()) {
+//      WXLogUtils.w("BoxShadow", "box-shadow disabled");
+      return;
+    }
+
+    if (getStyles() != null) {
+      Object obj = getStyles().get(Constants.Name.BOX_SHADOW);
+      if (obj == null) {
+        return;
+      }
+    }
+
+    View target = mHost;
+    if (this instanceof WXVContainer) {
+      target = ((WXVContainer) this).getBoxShadowHost(true);
+    }
+
+    if (target != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+      ViewOverlay overlay = target.getOverlay();
+      if (overlay != null) {
+        overlay.clear();
+      }
+    }
+    mLastBoxShadowId = null;
+  }
+
+  /**
+   * After component's layout result is apply to view. May be invoke multiple times since
+   * DOM can be changed in js runtime.
+   */
+  protected void onFinishLayout() {
+    Object param = getStyles() != null ? getStyles().get(Constants.Name.BACKGROUND_IMAGE) : null;
+    if (param != null) {
+      setBackgroundImage(param.toString());
+    }
+  }
+
+  /**
+   * measure
+   */
+  protected MeasureOutput measure(int width, int height) {
+    MeasureOutput measureOutput = new MeasureOutput();
+
+    if (mFixedProp != 0) {
+      measureOutput.width = mFixedProp;
+      measureOutput.height = mFixedProp;
+    } else {
+      measureOutput.width = width;
+      measureOutput.height = height;
+    }
+    return measureOutput;
+  }
+
+  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+  protected void setAriaHidden(boolean isHidden) {
+    View host = getHostView();
+    if (host != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+      host.setImportantForAccessibility(isHidden ? View.IMPORTANT_FOR_ACCESSIBILITY_NO : View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+    }
+  }
+
+  protected void setAriaLabel(String label) {
+    View host = getHostView();
+    if (host != null) {
+      host.setContentDescription(label);
+    }
+  }
+
+  protected void setRole(String roleKey) {
+    View host = getHostView();
+    String role = roleKey;
+    if (host != null && !TextUtils.isEmpty(roleKey)) {
+      IWXAccessibilityRoleAdapter roleAdapter = WXSDKManager.getInstance().getAccessibilityRoleAdapter();
+      if (roleAdapter != null) {
+        role = roleAdapter.getRole(roleKey);
+      }
+      final String finalRole = role;
+      AccessibilityDelegateCompat delegate = new AccessibilityDelegateCompat() {
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+          try {
+            super.onInitializeAccessibilityNodeInfo(host, info);
+            info.setRoleDescription(finalRole);
+          } catch (Throwable e) {
+            WXLogUtils.e("SetRole failed!");
+          }
+        }
+      };
+      ViewCompat.setAccessibilityDelegate(host, delegate);
+    }
+  }
+
+  /**
+   * Avoid large size view fail in GPU-Animation.
+   *
+   * @param fixedSize
+   */
+  private void setFixedSize(String fixedSize) {
+    if (PROP_FS_MATCH_PARENT.equals(fixedSize)) {
+      mFixedProp = ViewGroup.LayoutParams.MATCH_PARENT;
+    } else if (PROP_FS_WRAP_CONTENT.equals(fixedSize)) {
+      mFixedProp = ViewGroup.LayoutParams.WRAP_CONTENT;
+    } else {
+      mFixedProp = 0;
+      return;
+    }
+    if (mHost != null) {
+      ViewGroup.LayoutParams layoutParams = mHost.getLayoutParams();
+      if (layoutParams != null) {
+        layoutParams.height = mFixedProp;
+        layoutParams.width = mFixedProp;
+        mHost.setLayoutParams(layoutParams);
+      }
+    }
+  }
+
+  /**
+   * Add new event to component,this will post a task to DOM thread to add event.
+   *
+   * @param type
+   */
+  protected void appendEventToDOM(String type) {
+//    WXSDKManager.getInstance().getWXDomManager().postAction(getInstanceId(), Actions.getAddEvent(getRef(), type), false);
+  }
+
+  public View getRealView() {
+    return mHost;
+  }
+
+  /**
+   * Judge whether need to set an onTouchListener.<br>
+   * As there is only one onTouchListener in each view, so all the gesture that use onTouchListener should put there.
+   *
+   * @param type eventType {@link Event}
+   * @return true for set an onTouchListener, otherwise false
+   */
+  private boolean needGestureDetector(String type) {
+    if (mHost != null) {
+      for (WXGestureType gesture : WXGestureType.LowLevelGesture.values()) {
+        if (type.equals(gesture.toString())) {
+          return true;
+        }
+      }
+      for (WXGestureType gesture : WXGestureType.HighLevelGesture.values()) {
+        if (type.equals(gesture.toString())) {
+          return true;
+        }
+      }
+    }
+    if(WXGesture.isStopPropagation(type)){
+      return  true;
+    }
+    return false;
+  }
+
+  /**
+   * get Scroller components
+   */
+  public Scrollable getParentScroller() {
+    WXComponent component = this;
+    WXVContainer container;
+    Scrollable scroller;
+    for (; ; ) {
+      container = component.getParent();
+      if (container == null) {
+        return null;
+      }
+      if (container instanceof Scrollable) {
+        scroller = (Scrollable) container;
+        return scroller;
+      }
+      if (container.getRef().equals(ROOT)) {
+        return null;
+      }
+      component = container;
+    }
+  }
+
+  /**
+   * get Scroller components
+   */
+  @Nullable
+  public Scrollable getFirstScroller() {
+    if (this instanceof Scrollable) {
+      return (Scrollable) this;
+    }
+    return null;
+  }
+
+  public WXVContainer getParent() {
+    return mParent;
+  }
+
+  /**
+   * create view
+   */
+  public final void createView() {
+    if (!isLazy()) {
+      createViewImpl();
+    }
+  }
+
+  protected void createViewImpl() {
+    if (mContext != null) {
+      mHost = initComponentHostView(mContext);
+      if (mHost == null && !isVirtualComponent()) {
+        //compatible
+        initView();
+      }
+      if (mHost != null) {
+        if(mHost.getId() == View.NO_ID)
+          mHost.setId(WXViewUtils.generateViewId());
+        if(TextUtils.isEmpty(mHost.getContentDescription()) && WXEnvironment.isApkDebugable()){
+          mHost.setContentDescription(getRef());
+        }
+        ComponentObserver observer;
+        if ((observer = getInstance().getComponentObserver()) != null) {
+          observer.onViewCreated(this, mHost);
+        }
+      }
+      onHostViewInitialized(mHost);
+    } else {
+      WXLogUtils.e("createViewImpl", "Context is null");
+    }
+  }
+
+  /**
+   * Use {@link #initComponentHostView(Context context)} instead.
+   */
+  @Deprecated
+  protected void initView() {
+    if (mContext != null)
+      mHost = initComponentHostView(mContext);
+  }
+
+
+  /**
+   * Create corresponding view for this component.
+   *
+   * @param context
+   * @return
+   */
+  protected T initComponentHostView(@NonNull Context context) {
+    /**
+     * compatible old initView
+     */
+    return null;
+  }
+
+  /**
+   * Called after host view init. <br>
+   * Any overriding methods should invoke this method at the right time, to ensure the cached animation can be triggered correctly.
+   * (the animation will be cached when {@link #isLazy()} is true)
+   *
+   * @param host the host view
+   */
+  @CallSuper
+  protected void onHostViewInitialized(T host) {
+    if (mAnimationHolder != null) {
+//      Performs cached animation
+      mAnimationHolder.execute(mInstance, this);
+    }
+    setActiveTouchListener();
+  }
+
+  public T getHostView() {
+    return mHost;
+  }
+
+  /**
+   * use {@link #getHostView()} instead
+   *
+   * @return
+   */
+  @Deprecated
+  public View getView() {
+    return mHost;
+  }
+
+  public int getAbsoluteY() {
+    return mAbsoluteY;
+  }
+
+  public int getAbsoluteX() {
+    return mAbsoluteX;
+  }
+
+  public void removeEvent(String type) {
+    if (TextUtils.isEmpty(type)) {
+      return;
+    }
+
+    if (type.equals(Constants.Event.LAYEROVERFLOW))
+      removeLayerOverFlowListener(getRef());
+
+    if(getEvents() != null){
+      getEvents().remove(type);
+    }
+    if(mAppendEvents != null) {
+      mAppendEvents.remove(type);//only clean append events, not dom's events.
+    }
+    if(mGestureType != null){
+      mGestureType.remove(type);
+    }
+    removeEventFromView(type);
+  }
+
+  protected void removeEventFromView(String type) {
+    if (type.equals(Constants.Event.CLICK) && getRealView() != null && mHostClickListeners != null) {
+      if(mClickEventListener == null){
+        mClickEventListener = new OnClickListenerImp();
+      }
+      mHostClickListeners.remove(mClickEventListener);
+      //click event only remove from listener array
+    }
+    Scrollable scroller = getParentScroller();
+    if (type.equals(Constants.Event.APPEAR) && scroller != null) {
+      scroller.unbindAppearEvent(this);
+    }
+    if (type.equals(Constants.Event.DISAPPEAR) && scroller != null) {
+      scroller.unbindDisappearEvent(this);
+    }
+  }
+
+  public void removeAllEvent() {
+    if (getEvents().size() < 1) {
+      return;
+    }
+    WXEvent events = getEvents();
+    int size = events.size();
+    for (int i=0; i<size; i++) {
+      if(i >= events.size()){
+        break;
+      }
+      String event = events.get(i);
+      if (event == null) {
+        continue;
+      }
+      removeEventFromView(event);
+    }
+    if(mAppendEvents!=null) {
+      mAppendEvents.clear();//only clean append events, not dom's events.
+    }
+    if(mGestureType != null){
+      mGestureType.clear();
+    }
+    mGesture = null;
+    if (getRealView() != null &&
+            getRealView() instanceof WXGestureObservable) {
+      ((WXGestureObservable) getRealView()).registerGestureListener(null);
+    }
+    if (mHost != null) {
+      mHost.setOnFocusChangeListener(null);
+      if (mHostClickListeners != null && mHostClickListeners.size() > 0) {
+        mHostClickListeners.clear();
+        mHost.setOnClickListener(null);
+      }
+    }
+  }
+
+  public final void removeStickyStyle() {
+    if (isSticky()) {
+      Scrollable scroller = getParentScroller();
+      if (scroller != null) {
+        scroller.unbindStickStyle(this);
+      }
+    }
+  }
+
+  public boolean isSticky() {
+    return getStyles().isSticky();
+  }
+
+  public boolean isFixed() {
+    return getStyles().isFixed();
+  }
+
+  public void setDisabled(boolean disabled) {
+    mIsDisabled = disabled;
+    if (mHost == null) {
+      return;
+    }
+    mHost.setEnabled(!disabled);
+  }
+
+  public boolean isDisabled() {
+    return mIsDisabled;
+  }
+
+  public void setSticky(String sticky) {
+    if (!TextUtils.isEmpty(sticky) && sticky.equals(Constants.Value.STICKY)) {
+      Scrollable waScroller = getParentScroller();
+      if (waScroller != null) {
+        waScroller.bindStickStyle(this);
+      }
+    }
+  }
+
+  public void setBackgroundColor(String color) {
+    if (!TextUtils.isEmpty(color)) {
+      int colorInt = WXResourceUtils.getColor(color);
+      if (isRippleEnabled() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+        mRippleBackground = prepareBackgroundRipple();
+        if (mRippleBackground != null) {
+          if (mBackgroundDrawable == null) {
+            WXViewUtils.setBackGround(mHost, mRippleBackground, this);
+          } else {
+            LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{mRippleBackground, mBackgroundDrawable});
+            WXViewUtils.setBackGround(mHost, layerDrawable, this);
+          }
+          return;
+        }
+      }
+      if (!(colorInt == Color.TRANSPARENT && mBackgroundDrawable == null)) {
+        getOrCreateBorder().setColor(colorInt);
+      }
+    }
+  }
+
+  private Drawable prepareBackgroundRipple() {
+    try {
+      if (getStyles() != null && getStyles().getPesudoResetStyles() != null) {
+        Map<String, Object> resetStyles = getStyles().getPesudoResetStyles();
+
+        Object bgColor = resetStyles.get(Constants.Name.BACKGROUND_COLOR);
+        int colorInt = Color.TRANSPARENT;
+        if (bgColor != null) {
+          colorInt = WXResourceUtils.getColor(bgColor.toString(), Color.TRANSPARENT);
+          if (colorInt == Color.TRANSPARENT) {
+            return null;
+          }
+        }
+
+        Object bg = resetStyles.get(Constants.Name.BACKGROUND_COLOR + Constants.PSEUDO.ACTIVE);
+        if (bg == null) {
+          return null;
+        }
+        int rippleColor = WXResourceUtils.getColor(bg.toString(), colorInt);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+          ColorStateList colorStateList = new ColorStateList(
+                  new int[][]{new int[]{}},
+                  new int[]{rippleColor});
+          return new RippleDrawable(colorStateList, new ColorDrawable(colorInt), null) {
+            @Override
+            @SuppressLint("CanvasSize")
+            public void draw(@NonNull Canvas canvas) {
+              if (mBackgroundDrawable != null) {
+                Path border = mBackgroundDrawable.getContentPath(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()));
+                canvas.clipPath(border);
+              }
+              super.draw(canvas);
+            }
+          };
+        }
+      }
+    } catch (Throwable t) {
+      WXLogUtils.w("Exception on create ripple: ", t);
+    }
+    return null;
+  }
+
+  public void setBackgroundImage(@NonNull String bgImage) {
+    if ("".equals(bgImage.trim())) {
+      getOrCreateBorder().setImage(null);
+    } else {
+      Shader shader = WXResourceUtils.getShader(bgImage, getLayoutSize().getWidth(), getLayoutSize().getHeight());
+      getOrCreateBorder().setImage(shader);
+    }
+  }
+  private boolean shouldCancelHardwareAccelerate() {
+    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+    boolean cancel_hardware_accelerate = true;
+    if (adapter != null) {
+      try {
+        cancel_hardware_accelerate = Boolean.parseBoolean(adapter
+                .getConfig("android_weex_test_gpu",
+                        "cancel_hardware_accelerate",
+                        "true"));
+      }catch (Exception e){
+        WXLogUtils.e(WXLogUtils.getStackTrace(e));
+      }
+      WXLogUtils.i("cancel_hardware_accelerate : " + cancel_hardware_accelerate);
+    }
+    return cancel_hardware_accelerate;
+  }
+
+  public void setOpacity(float opacity) {
+    if (opacity >= 0 && opacity <= 1 && mHost.getAlpha() != opacity) {
+      int limit = WXRenderManager.getOpenGLRenderLimitValue();
+      if (isLayerTypeEnabled()) {
+        mHost.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+      }
+      if(isLayerTypeEnabled() && shouldCancelHardwareAccelerate() && limit > 0 && (getLayoutHeight() > limit ||
+              getLayoutWidth() > limit)){
+        mHost.setLayerType(View.LAYER_TYPE_NONE,null);
+      }
+      mHost.setAlpha(opacity);
+    }
+  }
+
+  public void setBorderRadius(String key, float borderRadius) {
+    if (borderRadius >= 0) {
+      switch (key) {
+        case Constants.Name.BORDER_RADIUS:
+          getOrCreateBorder().setBorderRadius(
+              CORNER.ALL, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
+          break;
+        case Constants.Name.BORDER_TOP_LEFT_RADIUS:
+          getOrCreateBorder().setBorderRadius(CORNER.BORDER_TOP_LEFT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
+          break;
+        case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
+          getOrCreateBorder().setBorderRadius(CORNER.BORDER_TOP_RIGHT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
+          break;
+        case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
+          getOrCreateBorder().setBorderRadius(CORNER.BORDER_BOTTOM_RIGHT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
+          break;
+        case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
+          getOrCreateBorder().setBorderRadius(CORNER.BORDER_BOTTOM_LEFT, WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getInstanceViewPortWidth()));
+          break;
+      }
+    }
+  }
+
+  public void setBorderWidth(String key, float borderWidth) {
+    if (borderWidth >= 0) {
+      switch (key) {
+        case Constants.Name.BORDER_WIDTH:
+          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.ALL, borderWidth);
+          break;
+        case Constants.Name.BORDER_TOP_WIDTH:
+          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.TOP, borderWidth);
+          break;
+        case Constants.Name.BORDER_RIGHT_WIDTH:
+          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.RIGHT, borderWidth);
+          break;
+        case Constants.Name.BORDER_BOTTOM_WIDTH:
+          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.BOTTOM, borderWidth);
+          break;
+        case Constants.Name.BORDER_LEFT_WIDTH:
+          getOrCreateBorder().setBorderWidth(CSSShorthand.EDGE.LEFT, borderWidth);
+          break;
+        default:
+          break;
+      }
+    }
+  }
+
+  public void setBorderStyle(String key, String borderStyle) {
+    if (!TextUtils.isEmpty(borderStyle)) {
+      switch (key) {
+        case Constants.Name.BORDER_STYLE:
+          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.ALL, borderStyle);
+          break;
+        case Constants.Name.BORDER_RIGHT_STYLE:
+          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.RIGHT, borderStyle);
+          break;
+        case Constants.Name.BORDER_BOTTOM_STYLE:
+          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.BOTTOM, borderStyle);
+          break;
+        case Constants.Name.BORDER_LEFT_STYLE:
+          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.LEFT, borderStyle);
+          break;
+        case Constants.Name.BORDER_TOP_STYLE:
+          getOrCreateBorder().setBorderStyle(CSSShorthand.EDGE.TOP, borderStyle);
+          break;
+      }
+    }
+  }
+
+  public void setBorderColor(String key, String borderColor) {
+    if (!TextUtils.isEmpty(borderColor)) {
+      int colorInt = WXResourceUtils.getColor(borderColor);
+      if (colorInt != Integer.MIN_VALUE) {
+        switch (key) {
+          case Constants.Name.BORDER_COLOR:
+            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.ALL, colorInt);
+            break;
+          case Constants.Name.BORDER_TOP_COLOR:
+            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.TOP, colorInt);
+            break;
+          case Constants.Name.BORDER_RIGHT_COLOR:
+            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.RIGHT, colorInt);
+            break;
+          case Constants.Name.BORDER_BOTTOM_COLOR:
+            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.BOTTOM, colorInt);
+            break;
+          case Constants.Name.BORDER_LEFT_COLOR:
+            getOrCreateBorder().setBorderColor(CSSShorthand.EDGE.LEFT, colorInt);
+            break;
+        }
+      }
+    }
+  }
+
+  public
+  @Nullable
+  String getVisibility() {
+    try {
+      return (String) getStyles().get(Constants.Name.VISIBILITY);
+    } catch (Exception e) {
+      return Constants.Value.VISIBLE;
+    }
+  }
+
+  public void setVisibility(String visibility) {
+    View view;
+    if ((view = getRealView()) != null) {
+      if (TextUtils.equals(visibility, Constants.Value.VISIBLE)) {
+        view.setVisibility(View.VISIBLE);
+      } else if (TextUtils.equals(visibility, Constants.Value.HIDDEN)) {
+        view.setVisibility(View.GONE);
+      }
+    }
+  }
+
+  /**
+   * This is an experimental feature for elevation of material design.
+   */
+  private void updateElevation() {
+    float elevation = getAttrs().getElevation(getInstance().getInstanceViewPortWidth());
+    if (!Float.isNaN(elevation)) {
+      ViewCompat.setElevation(getHostView(), elevation);
+    }
+  }
+
+  @Deprecated
+  public void registerActivityStateListener() {
+
+  }
+
+
+  /********************************
+   *  begin hook Activity life cycle callback
+   ********************************************************/
+  public void onActivityCreate() {
+
+  }
+
+  public void onActivityStart() {
+
+  }
+
+  public void onActivityPause() {
+
+  }
+
+  public void onActivityResume() {
+
+  }
+
+  public void onActivityStop() {
+
+  }
+
+  public void onActivityDestroy() {
+
+  }
+
+  public boolean onActivityBack() {
+    return false;
+  }
+
+  public void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+  }
+
+  public boolean onCreateOptionsMenu(Menu menu) {
+    return false;
+  }
+
+  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+
+  }
+
+  /********************************
+   *  end hook Activity life cycle callback
+   ********************************************************/
+  public void recycled() {
+    if (isFixed())
+      return;
+    clearBoxShadow();
+  }
+
+  public void destroy() {
+    ComponentObserver observer;
+    if ((observer = getInstance().getComponentObserver()) != null) {
+      observer.onPreDestory(this);
+    }
+
+    if (WXEnvironment.isApkDebugable() && !WXUtils.isUiThread()) {
+      throw new WXRuntimeException("[WXComponent] destroy can only be called in main thread");
+    }
+    if (mHost != null && mHost.getLayerType() == View.LAYER_TYPE_HARDWARE && isLayerTypeEnabled()) {
+      mHost.setLayerType(View.LAYER_TYPE_NONE, null);
+    }
+    removeAllEvent();
+    removeStickyStyle();
+
+    View view;
+    if (isFixed() && (view = getHostView()) != null) {
+      getInstance().removeFixedView(view);
+    }
+
+    if(contentBoxMeasurement!=null){
+      contentBoxMeasurement.destroy();
+      contentBoxMeasurement = null;
+    }
+    mIsDestroyed = true;
+    if(animations!=null) {
+      animations.clear();
+    }
+  }
+
+  public boolean isDestoryed() {
+    return mIsDestroyed;
+  }
+
+  /**
+   * Detach view from its component. Components,
+   * which have difference between getHostView and getRealView or have temp calculation results,
+   * must<strong> override</strong>  this method with their own implementation.
+   *
+   * @return the original View
+   */
+  public View detachViewAndClearPreInfo() {
+    View original = mHost;
+    mPreRealLeft = 0;
+    mPreRealRight = 0;
+    mPreRealWidth = 0;
+    mPreRealHeight = 0;
+    mPreRealTop = 0;
+//    mHost = null;
+    return original;
+  }
+
+  public void clearPreLayout() {
+    mPreRealLeft = 0;
+    mPreRealRight = 0;
+    mPreRealWidth = 0;
+    mPreRealHeight = 0;
+    mPreRealTop = 0;
+  }
+
+  /**
+   * This method computes user visible left-top point in view's coordinate.
+   * The default implementation uses the scrollX and scrollY of the view as the result,
+   * and put the value in the parameter pointer.
+   * Components with different computation algorithm
+   * <strong> should override </strong> this method.
+   *
+   * @param pointF the user visible left-top point in view's coordinate.
+   */
+  public void computeVisiblePointInViewCoordinate(PointF pointF) {
+    View view = getRealView();
+    pointF.set(view.getScrollX(), view.getScrollY());
+  }
+
+  public boolean containsGesture(WXGestureType WXGestureType) {
+    return mGestureType != null && mGestureType.contains(WXGestureType.toString());
+  }
+
+  public boolean containsEvent(String event) {
+    return getEvents().contains(event) || (mAppendEvents!=null && mAppendEvents.contains(event));
+  }
+
+  public void notifyAppearStateChange(String wxEventType, String direction) {
+    if (containsEvent(Constants.Event.APPEAR) || containsEvent(Constants.Event.DISAPPEAR)) {
+      Map<String, Object> params = new HashMap<>();
+      params.put("direction", direction);
+      fireEvent(wxEventType, params);
+    }
+  }
+
+  public boolean isUsing() {
+    return isUsing;
+  }
+
+  public void setUsing(boolean using) {
+    isUsing = using;
+  }
+
+  public void readyToRender() {
+    if (mParent != null && getInstance().isTrackComponent()) {
+      mParent.readyToRender();
+    }
+  }
+
+  public static class MeasureOutput {
+    public int width;
+    public int height;
+  }
+
+  /**
+   * Determine whether the current component needs to be placed in the real View tree
+   *
+   * @return false component add subview
+   */
+  public boolean isVirtualComponent() {
+    return mType == TYPE_VIRTUAL;
+  }
+
+  public void removeVirtualComponent() {
+  }
+
+  public int getType() {
+    return mType;
+  }
+
+  public boolean hasScrollParent(WXComponent component) {
+    if (component.getParent() == null) {
+      return true;
+    } else if (component.getParent() instanceof WXScroller) {
+      return false;
+    } else {
+      return hasScrollParent(component.getParent());
+    }
+  }
+
+  /**
+   * Called when property has empty value
+   *
+   * @param propName
+   */
+  @CheckResult
+  protected Object convertEmptyProperty(String propName, Object originalValue) {
+    switch (propName) {
+      case Constants.Name.BACKGROUND_COLOR:
+        return "transparent";
+      case Constants.Name.BORDER_RADIUS:
+      case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
+      case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
+      case Constants.Name.BORDER_TOP_LEFT_RADIUS:
+      case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
+        return 0;
+      case Constants.Name.BORDER_WIDTH:
+      case Constants.Name.BORDER_TOP_WIDTH:
+      case Constants.Name.BORDER_LEFT_WIDTH:
+      case Constants.Name.BORDER_RIGHT_WIDTH:
+      case Constants.Name.BORDER_BOTTOM_WIDTH:
+        return 0;
+      case Constants.Name.BORDER_COLOR:
+      case Constants.Name.BORDER_TOP_COLOR:
+      case Constants.Name.BORDER_LEFT_COLOR:
+      case Constants.Name.BORDER_RIGHT_COLOR:
+      case Constants.Name.BORDER_BOTTOM_COLOR:
+        return "black";
+    }
+    return originalValue;
+  }
+
+  private void setActiveTouchListener() {
+    boolean hasActivePesudo = getStyles().getPesudoStyles().containsKey(Constants.PSEUDO.ACTIVE);
+    View view;
+    if (hasActivePesudo && (view = getRealView()) != null) {
+      boolean hasTouchConsumer = isConsumeTouch();
+      view.setOnTouchListener(new TouchActivePseudoListener(this, !hasTouchConsumer));
+    }
+  }
+
+  protected boolean isConsumeTouch() {
+    return (mHostClickListeners != null && mHostClickListeners.size() > 0) || mGesture != null;
+  }
+
+  @Override
+  public void updateActivePseudo(boolean isSet) {
+    setPseudoClassStatus(Constants.PSEUDO.ACTIVE, isSet);
+  }
+
+  /**
+   * @param clzName like ':active' or ':active:enabled'
+   * @param status
+   */
+  protected void setPseudoClassStatus(String clzName, boolean status) {
+    WXStyle styles = getStyles();
+    Map<String, Map<String, Object>> pesudoStyles = styles.getPesudoStyles();
+
+    if (pesudoStyles == null || pesudoStyles.size() == 0) {
+      return;
+    }
+    if(mPesudoStatus == null){
+      mPesudoStatus = new PesudoStatus();
+    }
+    Map<String, Object> resultStyles = mPesudoStatus.updateStatusAndGetUpdateStyles(
+            clzName,
+            status,
+            pesudoStyles,
+            styles.getPesudoResetStyles());
+
+    if (null != resultStyles) {
+      if (status) {
+        mPseudoResetGraphicSize = new GraphicSize(getLayoutSize().getWidth(), getLayoutSize().getHeight());
+        if (resultStyles.keySet().contains(Constants.Name.WIDTH)) {
+          getLayoutSize().setWidth(WXViewUtils.getRealPxByWidth(WXUtils.parseFloat(styles.getPesudoResetStyles().get(Constants.Name.WIDTH + Constants.PSEUDO.ACTIVE)), getViewPortWidth()));
+        } else if (resultStyles.keySet().contains(Constants.Name.HEIGHT)){
+          getLayoutSize().setHeight(WXViewUtils.getRealPxByWidth(WXUtils.parseFloat(styles.getPesudoResetStyles().get(Constants.Name.HEIGHT + Constants.PSEUDO.ACTIVE)), getViewPortWidth()));
+        }
+      } else {
+        if (null != mPseudoResetGraphicSize) {
+          setLayoutSize(mPseudoResetGraphicSize);
+        }
+      }
+    }
+
+    updateStyleByPesudo(resultStyles);
+  }
+
+  private void updateStyleByPesudo(Map<String, Object> styles) {
+    new GraphicActionUpdateStyle(getInstance(), getRef(), styles, getPadding(), getMargin(), getBorder(), true)
+            .executeActionOnRender();
+    if (getLayoutWidth() == 0 && getLayoutWidth() == 0) {
+    } else {
+      WXBridgeManager.getInstance().setStyleWidth(getInstanceId(), getRef(), getLayoutWidth());
+      WXBridgeManager.getInstance().setStyleHeight(getInstanceId(), getRef(), getLayoutHeight());
+//      WXBridgeManager.getInstance().calculateLayout(getInstanceId(), getRef(), false);
+    }
+  }
+
+  public int getStickyOffset() {
+    return mStickyOffset;
+  }
+
+  public boolean canRecycled() {
+    return (!isFixed() || !isSticky()) && getAttrs().canRecycled();
+  }
+
+  /**
+   * Sets the offset for the sticky
+   *
+   * @param stickyOffset child[y]-parent[y]
+   */
+  public void setStickyOffset(int stickyOffset) {
+    mStickyOffset = stickyOffset;
+  }
+
+  /**
+   * For now, this method respect the result of {@link WXSDKInstance#isLayerTypeEnabled()}
+   *
+   * @return Refer {@link WXSDKInstance#isLayerTypeEnabled()}
+   */
+  public boolean isLayerTypeEnabled() {
+    return getInstance().isLayerTypeEnabled();
+  }
+
+  /**
+   * Sets whether or not to relayout page during animation, default is false
+   */
+  public void setNeedLayoutOnAnimation(boolean need) {
+    this.mNeedLayoutOnAnimation = need;
+  }
+
+  /**
+   * Trigger a updateStyles invoke to relayout current page
+   */
+  public void notifyNativeSizeChanged(int w, int h) {
+    if (!mNeedLayoutOnAnimation) {
+      return;
+    }
+
+    final WXBridgeManager manager = WXBridgeManager.getInstance();
+    manager.setStyleWidth(getInstanceId(), getRef(), w);
+    manager.setStyleHeight(getInstanceId(), getRef(), h);
+  }
+
+  public static final int STATE_DOM_FINISH = 0;
+  public static final int STATE_UI_FINISH = 1;
+  public static final int STATE_ALL_FINISH = 2;
+  @IntDef({STATE_DOM_FINISH, STATE_UI_FINISH, STATE_ALL_FINISH})
+  @Retention(RetentionPolicy.SOURCE)
+  @Target(ElementType.PARAMETER)
+  public @interface RenderState {
+  }
+
+  @CallSuper
+  public void onRenderFinish(@RenderState int state) {
+    if (WXTracing.isAvailable()) {
+      double uiTime = Stopwatch.nanosToMillis(mTraceInfo.uiThreadNanos);
+      if (state == STATE_ALL_FINISH || state == STATE_DOM_FINISH) {
+        WXTracing.TraceEvent domEvent = WXTracing.newEvent("DomExecute", getInstanceId(), mTraceInfo.rootEventId);
+        domEvent.ph = "X";
+        domEvent.ts = mTraceInfo.domThreadStart;
+        domEvent.tname = "DOMThread";
+        domEvent.name = getComponentType();
+        domEvent.classname = getClass().getSimpleName();
+        if (getParent() != null) {
+          domEvent.parentRef = getParent().getRef();
+        }
+        domEvent.submit();
+      }
+
+      if (state == STATE_ALL_FINISH || state == STATE_UI_FINISH) {
+        if (mTraceInfo.uiThreadStart != -1) {
+          WXTracing.TraceEvent uiEvent = WXTracing.newEvent("UIExecute", getInstanceId(), mTraceInfo.rootEventId);
+          uiEvent.ph = "X";
+          uiEvent.duration = uiTime;
+          uiEvent.ts = mTraceInfo.uiThreadStart;
+          uiEvent.name = getComponentType();
+          uiEvent.classname = getClass().getSimpleName();
+          if (getParent() != null) {
+            uiEvent.parentRef = getParent().getRef();
+          }
+          uiEvent.submit();
+        } else {
+          if (WXEnvironment.isApkDebugable() && !isLazy()) {
+//            WXLogUtils.w("onRenderFinish", "createView() not called");
+          }
+        }
+      }
+    }
+  }
+
+  protected boolean isRippleEnabled() {
+    try {
+      Object obj = getAttrs().get(Constants.Name.RIPPLE_ENABLED);
+      return WXUtils.getBoolean(obj, false);
+    } catch (Throwable t) {
+      //ignore
+    }
+    return false;
+  }
+
+  public boolean isWaste() {
+    return waste;
+  }
+
+  /**
+   * mark node waste,
+   * if node is waster should hidden, and dom tree should allow not show
+   * */
+  public void setWaste(boolean waste) {
+    if(this.waste != waste){
+      this.waste = waste;
+      if(!WXBasicComponentType.RECYCLE_LIST.equals(getParent().getComponentType())){
+          NativeRenderObjectUtils.nativeRenderObjectChildWaste(getRenderObjectPtr(), waste);
+      }
+
+     if(waste){
+        //update dom not show, and put style to hidden
+        getStyles().put(Constants.Name.VISIBILITY, Constants.Value.HIDDEN);
+        //if component not init, mark lazy init when use, reduce view count
+        if(getHostView() == null){
+          if(!mLazy){
+            lazy(true);
+          }
+        }else{
+          getHostView().setVisibility(View.GONE);
+        }
+      }else{
+       getStyles().put(Constants.Name.VISIBILITY, Constants.Value.VISIBLE);
+        if(getHostView() == null){
+          if(mLazy) { // when parent is lazy just mark node lazy false
+            if(mParent != null && mParent.isLazy()){
+              lazy(false);
+            }else{
+              Statements.initLazyComponent(this, mParent);
+            }
+          }
+        }else{
+          getHostView().setVisibility(View.VISIBLE);
+        }
+      }
+    }
+  }
+
+
+  /** component uniquie key id in native for recycle-list,
+   *  should be unique for every native component differ with ref
+   *  */
+  public  String getViewTreeKey(){
+    if(mViewTreeKey == null){
+      if(getParent() == null){
+        mViewTreeKey = hashCode() + "_" + getRef();
+      }else{
+        mViewTreeKey = hashCode() + "_" + getRef() + "_" + getParent().indexOf(this);
+      }
+    }
+    return mViewTreeKey;
+  }
+
+  private String mViewTreeKey;
+
+  public WXTransition getTransition() {
+    return mTransition;
+  }
+
+  public void setTransition(WXTransition transition) {
+    this.mTransition = transition;
+  }
+
+  public void addAnimationForElement(Map<String, Object> animMap) {
+    if(animMap!=null && !animMap.isEmpty()){
+      if(animations == null){
+        animations = new ConcurrentLinkedQueue<>();
+      }
+      animations.add(new Pair<>(getRef(),animMap));
+    }
+  }
+
+  private void parseAnimation() {
+    if (null == animations) {
+      return;
+    }
+    for (final Pair<String, Map<String, Object>> pair : animations) {
+      if (!TextUtils.isEmpty(pair.first)) {
+        final WXAnimationBean animationBean = createAnimationBean(pair.first, pair.second);
+        if (animationBean != null) {
+          GraphicActionAnimation action = new GraphicActionAnimation(getInstance(), getRef(), animationBean);
+          action.executeAction();
+        }
+      }
+    }
+    animations.clear();
+  }
+
+
+  private WXAnimationBean createAnimationBean(String ref,Map<String, Object> style){
+    if (style != null) {
+      try {
+        Object transform = style.get(Constants.Name.TRANSFORM);
+        if (transform instanceof String && !TextUtils.isEmpty((String) transform)) {
+          String transformOrigin = (String) style.get(Constants.Name.TRANSFORM_ORIGIN);
+          WXAnimationBean animationBean = new WXAnimationBean();
+          int width = (int) getLayoutWidth();
+          int height = (int) getLayoutHeight();
+          animationBean.styles = new WXAnimationBean.Style();
+          animationBean.styles.init(transformOrigin, (String) transform, width, height,WXSDKManager.getInstanceViewPortWidth(getInstanceId()),
+                  getInstance());
+          return animationBean;
+        }
+      }catch (RuntimeException e){
+        WXLogUtils.e("", e);
+        return null;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * node is lazy
+   * */
+  private boolean mLazy = false;
+
+  /***/
+  public void lazy(boolean lazy) {
+    mLazy = lazy;
+  }
+
+  public long getRenderObjectPtr(){
+    if(getBasicComponentData().isRenderPtrEmpty()){
+      getBasicComponentData().setRenderObjectPr(NativeRenderObjectUtils.nativeGetRenderObject(getInstanceId(), getRef()));
+    }
+    return getBasicComponentData().getRenderObjectPr();
+  }
+
+
+  public void updateNativeAttr(String key, Object value){
+    if(key == null){
+      return;
+    }
+    if(value == null){
+      value  = "";
+    }
+    getBasicComponentData().getAttrs().put(key, value);
+    NativeRenderObjectUtils.nativeUpdateRenderObjectAttr(getRenderObjectPtr(), key, value.toString());
+  }
+
+  public  void  nativeUpdateAttrs(Map<String, Object> dynamic){
+    Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
+    /**
+     * diff attrs, see attrs has update, remove none update attrs
+     * */
+    Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
+    while (iterator.hasNext()){
+      Map.Entry<String, Object> objectEntry = iterator.next();
+      if(objectEntry.getKey() == null){
+        continue;
+      }
+      updateNativeAttr(objectEntry.getKey(), objectEntry.getValue());
+    }
+  }
+
+
+  public void updateNativeStyle(String key, Object value){
+    if(key == null){
+      return;
+    }
+    if(value == null){
+      value  = "";
+    }
+    getBasicComponentData().getStyles().put(key, value);
+    NativeRenderObjectUtils.nativeUpdateRenderObjectStyle(getRenderObjectPtr(), key, value.toString());
+  }
+
+  public  void  updateNativeStyles(Map<String, Object> dynamic){
+    Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
+    /**
+     * diff attrs, see attrs has update, remove none update attrs
+     * */
+    Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
+    while (iterator.hasNext()){
+      Map.Entry<String, Object> objectEntry = iterator.next();
+      if(objectEntry.getKey() == null){
+        continue;
+      }
+      updateNativeStyle(objectEntry.getKey(), objectEntry.getValue());
+    }
+  }
+
+  public void addLayerOverFlowListener(String ref) {
+    if (getInstance() != null)
+      getInstance().addLayerOverFlowListener(ref);
+  }
+
+  public void removeLayerOverFlowListener(String ref) {
+    if (getInstance() != null)
+      getInstance().removeLayerOverFlowListener(ref);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponentFactory.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponentFactory.java
new file mode 100644
index 0000000..7a4290c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponentFactory.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.text.TextUtils;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.ui.IFComponentHolder;
+import org.apache.weex.ui.WXComponentRegistry;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+
+/**
+ * Component factory
+ */
+public class WXComponentFactory {
+
+  public static WXComponent newInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    if (instance == null || TextUtils.isEmpty(basicComponentData.mComponentType)) {
+      return null;
+    }
+
+    IFComponentHolder holder = WXComponentRegistry.getComponent(basicComponentData.mComponentType);
+    if (holder == null) {
+      if (WXEnvironment.isApkDebugable()) {
+        String tag = "WXComponentFactory error type:[" +
+                basicComponentData.mComponentType + "]" + " class not found";
+        WXLogUtils.e(tag);
+      }
+      //For compatible reason of JS framework, unregistered type will be treated as container.
+      holder = WXComponentRegistry.getComponent(WXBasicComponentType.CONTAINER);
+      if (holder == null) {
+        WXExceptionUtils.commitCriticalExceptionRT(instance.getInstanceId(),
+                WXErrorCode.WX_RENDER_ERR_COMPONENT_NOT_REGISTER, "createComponent",
+                basicComponentData.mComponentType + " not registered", null);
+        return null;
+      }
+    }
+
+    try {
+      return holder.createInstance(instance, parent, basicComponentData);
+    } catch (Throwable e) {
+      WXLogUtils.e("WXComponentFactory Exception type:[" + basicComponentData.mComponentType + "] ", e);
+    }
+
+    return null;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponentProp.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponentProp.java
new file mode 100644
index 0000000..d2a8fbf
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXComponentProp.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface WXComponentProp {
+
+  String name();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXDiv.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXDiv.java
new file mode 100644
index 0000000..e22acd7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXDiv.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.flat.FlatComponent;
+import org.apache.weex.ui.flat.WidgetContainer;
+import org.apache.weex.ui.flat.widget.WidgetGroup;
+import org.apache.weex.ui.view.WXFrameLayout;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedList;
+
+/**
+ * div component
+ */
+@Component(lazyload = false)
+public class WXDiv extends WidgetContainer<WXFrameLayout> implements FlatComponent<WidgetGroup> {
+
+  private WidgetGroup mWidgetGroup;
+
+  public static class Ceator implements ComponentCreator {
+    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      return new WXDiv(instance, parent, basicComponentData);
+    }
+  }
+
+  @Deprecated
+  public WXDiv(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXDiv(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  @Override
+  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
+    WXFrameLayout frameLayout = new WXFrameLayout(context);
+    frameLayout.holdComponent(this);
+    return frameLayout;
+  }
+
+  @Override
+  public boolean promoteToView(boolean checkAncestor) {
+    if (null != getInstance().getFlatUIContext()) {
+      return !intendToBeFlatContainer() ||
+            getInstance().getFlatUIContext().promoteToView(this, checkAncestor, WXDiv.class);
+    }
+    return false;
+  }
+
+  /**
+   * Create View tree there. Either this method or {@link #createViewImpl()} get called.
+   * If this object will be promoted to view, then getOrCreateFlatWidget() should never be called.
+   */
+  @Override
+  @NonNull
+  public WidgetGroup getOrCreateFlatWidget() {
+    if (mWidgetGroup == null) {
+      mWidgetGroup = new WidgetGroup(getInstance().getFlatUIContext());
+      for (int i = 0; i < getChildCount(); i++) {
+        createChildViewAt(i);
+      }
+      mountFlatGUI();
+    }
+    return mWidgetGroup;
+  }
+
+  @Override
+  protected void mountFlatGUI() {
+    if(widgets == null){
+      widgets = new LinkedList<>();
+    }
+    if (promoteToView(true)) {
+      if(getHostView()!=null) {
+        getHostView().mountFlatGUI(widgets);
+      }
+    } else {
+      mWidgetGroup.replaceAll(widgets);
+    }
+  }
+
+  @Override
+  public void unmountFlatGUI() {
+    if (getHostView() != null) {
+      getHostView().unmountFlatGUI();
+    }
+  }
+
+  @Override
+  public boolean intendToBeFlatContainer() {
+    return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXDiv.class.equals(getClass());
+  }
+
+  @Override
+  public boolean isVirtualComponent() {
+    return !promoteToView(true);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXEmbed.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXEmbed.java
new file mode 100644
index 0000000..2687095
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXEmbed.java
@@ -0,0 +1,646 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.annotation.SuppressLint;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import org.apache.weex.R;
+import org.apache.weex.IWXRenderListener;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.OnWXScrollListener;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXRenderStrategy;
+import org.apache.weex.instance.InstanceOnFireEventInterceptor;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.ArrayDeque;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import org.apache.weex.WXSDKInstance.OnInstanceVisibleListener;
+
+@Component(lazyload = false)
+public class WXEmbed extends WXDiv implements OnInstanceVisibleListener,NestedContainer {
+
+  public static final  String STRATEGY_NONE =  "none";
+  public static final  String STRATEGY_NORMAL =  "normal";
+  public static final  String STRATEGY_HIGH =  "high";
+
+
+  public static final  String PRIORITY_LOW =  "low";
+  public static final  String PRIORITY_NORMAL =  "normal";
+  public static final  String PRIORITY_HIGH =  "high";
+
+  public static final String ITEM_ID = "itemId";
+
+  private String src;
+  protected WXSDKInstance mNestedInstance;
+  private static int ERROR_IMG_WIDTH = (int) WXViewUtils.getRealPxByWidth(270,750);
+  private static int ERROR_IMG_HEIGHT = (int) WXViewUtils.getRealPxByWidth(260,750);
+
+  private boolean mIsVisible = true;
+  private EmbedRenderListener mListener;
+  private EmbedInstanceOnScrollFireEventInterceptor mInstanceOnScrollFireEventInterceptor;
+
+
+  private String priority = PRIORITY_NORMAL;
+
+  private String strategy = "normal";  //none, normal, high(ignore priority)
+
+  private long hiddenTime;
+
+
+
+  public interface EmbedManager {
+    WXEmbed getEmbed(String itemId);
+    void putEmbed(String itemId,WXEmbed comp);
+  }
+
+  public static class FailToH5Listener extends ClickToReloadListener {
+    @SuppressLint("SetJavaScriptEnabled")
+    @Override
+    public void onException(NestedContainer comp, String errCode, String msg) {
+      //downgrade embed
+      if( errCode != null && comp instanceof WXEmbed && errCode.startsWith("1|")) {
+        ViewGroup container = comp.getViewContainer();
+        WebView webView = new WebView(container.getContext());
+        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+        webView.setLayoutParams(params);
+        webView.getSettings().setJavaScriptEnabled(true);
+
+        //WebView Remote Code Execution Vulnerability
+        webView.removeJavascriptInterface("searchBoxJavaBridge_");
+        webView.removeJavascriptInterface("accessibility");
+        webView.removeJavascriptInterface("accessibilityTraversal");
+        webView.getSettings().setSavePassword(false);
+
+        container.removeAllViews();
+        container.addView(webView);
+        webView.loadUrl(((WXEmbed) comp).src);
+      }else{
+        super.onException(comp,errCode,msg);
+      }
+    }
+  }
+
+  /**
+   * Default event listener.
+   */
+  public static class ClickToReloadListener implements OnNestedInstanceEventListener {
+    @Override
+    public void onException(NestedContainer container, String errCode, String msg) {
+      if (TextUtils.equals(errCode, WXErrorCode.
+              WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode()) && container instanceof WXEmbed) {
+        final WXEmbed comp = ((WXEmbed)container);
+        final ImageView imageView = new ImageView(comp.getContext());
+        imageView.setImageResource(R.drawable.weex_error);
+        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ERROR_IMG_WIDTH, ERROR_IMG_HEIGHT);
+        layoutParams.gravity = Gravity.CENTER;
+        imageView.setLayoutParams(layoutParams);
+        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
+        imageView.setAdjustViewBounds(true);
+        imageView.setOnClickListener(new View.OnClickListener() {
+          @Override
+          public void onClick(View v) {
+            imageView.setOnClickListener(null);
+            imageView.setEnabled(false);
+            comp.loadContent();
+          }
+        });
+        FrameLayout hostView = comp.getHostView();
+        hostView.removeAllViews();
+        hostView.addView(imageView);
+        WXLogUtils.e("WXEmbed", "NetWork failure :" + errCode + ",\n error message :" + msg);
+      }
+    }
+
+    @Override
+    public boolean onPreCreate(NestedContainer comp, String src) {
+      return true;
+    }
+
+    @Override
+    public String transformUrl(String origin) {
+      return origin;
+    }
+
+    @Override
+    public void onCreated(NestedContainer comp, WXSDKInstance nestedInstance) {
+
+    }
+  }
+
+  static class EmbedRenderListener implements IWXRenderListener {
+    WXEmbed mComponent;
+    OnNestedInstanceEventListener mEventListener;
+
+    EmbedRenderListener(WXEmbed comp) {
+      mComponent = comp;
+      mEventListener = new ClickToReloadListener();
+    }
+
+    @Override
+    public void onViewCreated(WXSDKInstance instance, View view) {
+      FrameLayout hostView = mComponent.getHostView();
+      hostView.removeAllViews();
+      hostView.addView(view);
+    }
+
+    @Override
+    public void onRenderSuccess(WXSDKInstance instance, int width, int height) {
+
+    }
+
+    @Override
+    public void onRefreshSuccess(WXSDKInstance instance, int width, int height) {
+
+    }
+
+    @Override
+    public void onException(WXSDKInstance instance, String errCode, String msg) {
+      if (mEventListener != null) {
+        mEventListener.onException(mComponent, errCode, msg);
+      }
+    }
+  }
+
+  @Deprecated
+  public WXEmbed(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXEmbed(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+    mListener = new EmbedRenderListener(this);
+    mInstanceOnScrollFireEventInterceptor = new EmbedInstanceOnScrollFireEventInterceptor(this);
+
+    ERROR_IMG_WIDTH = (int) WXViewUtils.getRealPxByWidth(270, instance.getInstanceViewPortWidth());
+    ERROR_IMG_HEIGHT = (int) WXViewUtils.getRealPxByWidth(260, instance.getInstanceViewPortWidth());
+    if (instance instanceof EmbedManager) {
+      Object itemId = getAttrs().get(ITEM_ID);
+      if (itemId != null) {
+        ((EmbedManager) instance).putEmbed(itemId.toString(), this);
+      }
+    }
+    this.priority = WXUtils.getString(getAttrs().get(Constants.Name.PRIORITY), PRIORITY_NORMAL);
+    this.strategy = WXUtils.getString(getAttrs().get(Constants.Name.STRATEGY), STRATEGY_NONE);
+    instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_EMBED_COUNT,1);
+  }
+
+  @Override
+  public void setOnNestEventListener(OnNestedInstanceEventListener listener){
+    mListener.mEventListener = listener;
+  }
+
+  @Override
+  public ViewGroup getViewContainer() {
+    return getHostView();
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.SRC:
+        String src = WXUtils.getString(param, null);
+        if (src != null)
+          setSrc(src);
+        return true;
+      case Constants.Name.PRIORITY:
+        String priority = WXUtils.getString(param, null);
+        if (priority != null) {
+          setPriority(priority);
+        }
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @Override
+  public void renderNewURL(String url) {
+    src = url;
+    loadContent();
+  }
+
+  @Override
+  public void reload() {
+    if (!TextUtils.isEmpty(src)) {
+      loadContent();
+    }
+  }
+
+  public String getOriginUrl() {
+    return originUrl;
+  }
+
+  public void setOriginUrl(String originUrl) {
+    this.originUrl = originUrl;
+  }
+
+  private String originUrl;
+
+
+  @Override
+  public void addEvent(String type) {
+    super.addEvent(type);
+    if(Constants.Event.SCROLL_START.equals(type)){
+      mInstanceOnScrollFireEventInterceptor.addInterceptEvent(type);
+    }else if(Constants.Event.SCROLL_END.equals(type)){
+      mInstanceOnScrollFireEventInterceptor.addInterceptEvent(type);
+    }else if(Constants.Event.SCROLL.equals(type)){
+      mInstanceOnScrollFireEventInterceptor.addInterceptEvent(type);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SRC)
+  public void setSrc(String src) {
+    originUrl=src;
+    this.src = src;
+    if (mNestedInstance != null) {
+      mNestedInstance.destroy();
+      mNestedInstance = null;
+    }
+    if (mIsVisible && !TextUtils.isEmpty(this.src)) {
+      loadContent();
+    }
+  }
+  public String getSrc() {
+    return src;
+  }
+
+
+  @WXComponentProp(name = Constants.Name.PRIORITY)
+  public void setPriority(String priority) {
+    if(TextUtils.isEmpty(priority)){
+      return;
+    }
+    this.priority = priority;
+  }
+
+  /**
+   * Load embed content, default behavior is create a nested instance.
+   */
+  protected void loadContent(){
+    if(mNestedInstance != null){
+      mNestedInstance.destroy();
+    }
+    mNestedInstance = createInstance();
+    if(mListener != null && mListener.mEventListener != null){
+      if(!mListener.mEventListener.onPreCreate(this,src)){
+        //cancel render
+        mListener.mEventListener.onCreated(this, mNestedInstance);
+      }
+    }
+  }
+
+  private static final int getLevel(WXEmbed embed){
+    String priority = embed.priority;
+    String strategy = embed.strategy;
+    int level  = 5;
+    if(!STRATEGY_HIGH.equals(strategy)) {
+      if (TextUtils.equals(priority, PRIORITY_LOW)) {
+        level = 0;
+      } else if (TextUtils.equals(priority, PRIORITY_HIGH)) {
+        level = 10;
+      }
+    }
+    return  level;
+  }
+
+  private WXSDKInstance createInstance() {
+    WXSDKInstance sdkInstance = getInstance().createNestedInstance(this);
+    sdkInstance.setParentInstance(getInstance());
+    boolean needsAdd = !getAttrs().containsKey("disableInstanceVisibleListener");
+    if(needsAdd){ //prevent switch off fire viewappear event twice
+        getInstance().addOnInstanceVisibleListener(this);
+    }
+    sdkInstance.registerRenderListener(mListener);
+    mInstanceOnScrollFireEventInterceptor.resetFirstLaterScroller();;
+    sdkInstance.addInstanceOnFireEventInterceptor(mInstanceOnScrollFireEventInterceptor);
+    sdkInstance.registerOnWXScrollListener(mInstanceOnScrollFireEventInterceptor);
+
+    String url=src;
+    if(mListener != null && mListener.mEventListener != null){
+      url=mListener.mEventListener.transformUrl(src);
+      if(!mListener.mEventListener.onPreCreate(this,src)){
+        //cancel render
+        return null;
+      }
+    }
+
+    if(TextUtils.isEmpty(url)){
+      mListener.mEventListener.onException(this,
+              WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode(),
+              WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorMsg() + "!!wx embed src url is null"
+      );
+      return sdkInstance;
+    }
+    sdkInstance.setContainerInfo(WXInstanceApm.KEY_PAGE_PROPERTIES_INSTANCE_TYPE,"embed");
+    sdkInstance.setContainerInfo(WXInstanceApm.KEY_PAGE_PROPERTIES_PARENT_PAGE,getInstance().getWXPerformance().pageName);
+    sdkInstance.renderByUrl(url,
+            url,
+            null, null,
+            WXRenderStrategy.APPEND_ASYNC);
+
+    return sdkInstance;
+  }
+
+  @Override
+  public void setVisibility(String visibility) {
+    super.setVisibility(visibility);
+    boolean visible = TextUtils.equals(visibility, Constants.Value.VISIBLE);
+    if(mIsVisible != visible){
+
+      if (!TextUtils.isEmpty(src) && visible) {
+        if (mNestedInstance == null) {
+          loadContent();
+        } else {
+          mNestedInstance.onViewAppear();
+        }
+      }
+
+      if (!visible) {
+        if (mNestedInstance != null) {
+          mNestedInstance.onViewDisappear();
+        }
+      }
+      mIsVisible = visible;
+      doAutoEmbedMemoryStrategy();
+    }
+  }
+
+  @Override
+  public void destroy() {
+    super.destroy();
+    destoryNestInstance();
+    src = null;
+    if (getInstance() != null) {
+      getInstance().removeOnInstanceVisibleListener(this);
+    }
+  }
+
+  private void  doAutoEmbedMemoryStrategy(){
+    /**
+     * auto manage embed amount in current instance, save memory
+     * */
+    if(!STRATEGY_NONE.equals(this.strategy)){
+      if(!mIsVisible && mNestedInstance != null){
+        if(PRIORITY_LOW.equals(this.priority)){
+          destoryNestInstance();
+        }else{
+          if(getInstance().hiddenEmbeds == null){ // low is in front, when priority is same, hidden time pre in first
+            getInstance().hiddenEmbeds = new PriorityQueue<>(8, new Comparator<WXEmbed>() {
+              @Override
+              public int compare(WXEmbed o1, WXEmbed o2) {
+                int level =  getLevel(o1) - getLevel(o2);
+                if(level != 0){
+                  return  level;
+                }
+                return (int) (o1.hiddenTime - o2.hiddenTime);
+              }
+            });
+          }
+          //getInstance().hiddenEmbeds.remove(this);
+          if(!getInstance().hiddenEmbeds.contains(this)) {
+            this.hiddenTime = System.currentTimeMillis();
+            getInstance().hiddenEmbeds.add(this);
+          }
+          if(getInstance().hiddenEmbeds != null && getInstance().getMaxHiddenEmbedsNum() >= 0){
+            while (getInstance().hiddenEmbeds.size() > getInstance().getMaxHiddenEmbedsNum()){
+              WXEmbed embed = getInstance().hiddenEmbeds.poll();
+              if(embed.mIsVisible){
+                continue;
+              }
+              if(embed != null) {
+                embed.destoryNestInstance();
+              }
+            }
+          }
+        }
+      }
+      if(mIsVisible && mNestedInstance != null){
+        if(getInstance().hiddenEmbeds != null && getInstance().hiddenEmbeds.contains(this)){
+          getInstance().hiddenEmbeds.remove(this);
+        }
+      }
+    }
+
+  }
+
+  @Override
+  public void onAppear() {
+    //appear event from root instance will not trigger visibility change
+    if(mIsVisible && mNestedInstance != null){
+      WXComponent comp = mNestedInstance.getRootComponent();
+      if(comp != null)
+        comp.fireEvent(Constants.Event.VIEWAPPEAR);
+    }
+  }
+
+  @Override
+  public void onDisappear() {
+    //appear event from root instance will not trigger visibility change
+    if(mIsVisible && mNestedInstance != null){
+      WXComponent comp = mNestedInstance.getRootComponent();
+      if(comp != null)
+        comp.fireEvent(Constants.Event.VIEWDISAPPEAR);
+    }
+  }
+
+  @Override
+  public void onActivityStart() {
+    super.onActivityStart();
+    if (mNestedInstance != null) {
+      mNestedInstance.onActivityStart();
+    }
+  }
+
+  @Override
+  public void onActivityResume() {
+    super.onActivityResume();
+    if (mNestedInstance != null) {
+      mNestedInstance.onActivityResume();
+    }
+  }
+
+  @Override
+  public void onActivityPause() {
+    super.onActivityPause();
+    if (mNestedInstance != null) {
+      mNestedInstance.onActivityPause();
+    }
+  }
+
+  @Override
+  public void onActivityStop() {
+    super.onActivityStop();
+    if (mNestedInstance != null) {
+      mNestedInstance.onActivityStop();
+    }
+  }
+
+  @Override
+  public void onActivityDestroy() {
+    super.onActivityDestroy();
+    if (mNestedInstance != null) {
+      mNestedInstance.onActivityDestroy();
+    }
+  }
+
+  public void setStrategy(String strategy) {
+    this.strategy = strategy;
+  }
+
+  private void destoryNestInstance(){
+    if(getInstance().hiddenEmbeds != null && getInstance().hiddenEmbeds.contains(this)){
+      getInstance().hiddenEmbeds.remove(this);
+    }
+    if (mNestedInstance != null) {
+      mNestedInstance.destroy();
+      mNestedInstance = null;
+    }
+    if(WXEnvironment.isApkDebugable()){
+      WXLogUtils.w("WXEmbed destoryNestInstance priority " + priority + " index " + getAttrs().get("index")
+              + "  " + hiddenTime  + " embeds size " + (getInstance().hiddenEmbeds == null ?  0 : getInstance().hiddenEmbeds.size())
+              + " strategy " + this.strategy);
+    }
+  }
+
+  @Override
+  public void addLayerOverFlowListener(String ref) {
+    if (mNestedInstance != null)
+      mNestedInstance.addLayerOverFlowListener(getRef());
+  }
+
+  @Override
+  public void removeLayerOverFlowListener(String ref) {
+    if (mNestedInstance != null)
+      mNestedInstance.removeLayerOverFlowListener(ref);
+  }
+
+  static class EmbedInstanceOnScrollFireEventInterceptor extends
+      InstanceOnFireEventInterceptor implements OnWXScrollListener {
+
+    private WXEmbed mEmbed;
+    private WXComponent firstLayerScroller;
+
+    public EmbedInstanceOnScrollFireEventInterceptor(WXEmbed embed) {
+      this.mEmbed = embed;
+    }
+
+    public void resetFirstLaterScroller(){
+      firstLayerScroller = null;
+    }
+
+    @Override
+    public void onFireEvent(String instanceId, String elementRef, String type, Map<String, Object> params, Map<String, Object> domChanges) {
+      if(mEmbed == null
+              || mEmbed.mNestedInstance == null
+              || !mEmbed.mNestedInstance.getInstanceId().equals(instanceId)){
+        return;
+      }
+      if(firstLayerScroller == null){
+          initFirstLayerScroller();
+      }
+      if(firstLayerScroller == null){
+        return;
+      }
+      if(firstLayerScroller.getRef().equals(elementRef)){
+         mEmbed.getInstance().fireEvent(mEmbed.getRef(), type, params, domChanges);
+      }
+    }
+
+
+    private void initFirstLayerScroller(){
+      if(firstLayerScroller == null){
+          firstLayerScroller = findFirstLayerScroller();
+          if(firstLayerScroller != null){
+            for(String event : getListenEvents()){
+              if(!firstLayerScroller.containsEvent(event)){
+                  firstLayerScroller.getEvents().add(event);
+                  firstLayerScroller.addEvent(event);
+              }
+            }
+          }
+      }
+    }
+
+    /**
+     * get first layer scroller ref
+     * */
+    private WXComponent findFirstLayerScroller(){
+         if(mEmbed.mNestedInstance == null){
+           return null;
+         }
+         WXComponent rootComponent = mEmbed.mNestedInstance.getRootComponent();
+        if(rootComponent instanceof  Scrollable){
+          return rootComponent;
+        }
+        Queue<WXComponent> queues = new ArrayDeque<>();
+        queues.offer(rootComponent);
+        while (!queues.isEmpty()){
+             WXComponent component = queues.poll();
+             if(component == null){
+               break;
+             }
+             if(component instanceof  Scrollable){
+                return  component;
+             }
+             if(component instanceof WXVContainer){
+               WXVContainer container = (WXVContainer) component;
+               for(int i=0; i<container.getChildCount(); i++){
+                  queues.offer(container.getChild(i));
+               }
+             }
+        }
+        return null;
+    }
+
+
+    @Override
+    public void onScrolled(View view, int x, int y) {
+      if(firstLayerScroller != null){
+        return;
+      }
+      if(getListenEvents().size() > 0){
+        initFirstLayerScroller();
+      }
+    }
+
+    @Override
+    public void onScrollStateChanged(View view, int x, int y, int newState) {
+
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXHeader.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXHeader.java
new file mode 100644
index 0000000..4172cfa
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXHeader.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.list.WXCell;
+
+/**
+ * The same as sticky cell
+ */
+@Component(lazyload = false)
+public class WXHeader extends WXCell {
+
+  @Deprecated
+  public WXHeader(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  public WXHeader(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
+    super(instance, parent, lazy, basicComponentData);
+    String parantType = parent.getComponentType();
+    if(WXBasicComponentType.LIST.equals(parantType)
+            || WXBasicComponentType.RECYCLE_LIST.equals(parantType)){
+      getStyles().put(Constants.Name.POSITION, Constants.Value.STICKY);
+      setSticky(Constants.Value.STICKY);
+    }
+  }
+
+  @Override
+  public boolean isLazy() {
+    return false;
+  }
+
+  @Override
+  public boolean canRecycled() {
+    return !isSticky();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXImage.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXImage.java
new file mode 100644
index 0000000..dbb70d3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXImage.java
@@ -0,0 +1,549 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import org.apache.weex.dom.WXImageQuality;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.text.TextUtils;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.adapter.IWXImgLoaderAdapter;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXImageSharpen;
+import org.apache.weex.common.WXImageStrategy;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.performance.WXAnalyzerDataTransfer;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXImageView;
+import org.apache.weex.ui.view.border.BorderDrawable;
+import org.apache.weex.utils.ImageDrawable;
+import org.apache.weex.utils.ImgURIUtil;
+import org.apache.weex.utils.SingleFunctionParser;
+import org.apache.weex.utils.WXDomUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewToImageUtil;
+import org.apache.weex.utils.WXViewUtils;
+
+/**
+ * Image component
+ */
+@Component(lazyload = false)
+public class WXImage extends WXComponent<ImageView> {
+
+  public static final String SUCCEED = "success";
+  public static final String ERRORDESC = "errorDesc";
+  private static final int WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 0x2;
+
+  private String mSrc;
+  private int mBlurRadius;
+  private boolean mAutoRecycle = true;
+
+  private static SingleFunctionParser.FlatMapper<Integer> BLUR_RADIUS_MAPPER = new SingleFunctionParser.FlatMapper<Integer>() {
+    @Override
+    public Integer map(String raw) {
+      return WXUtils.getInteger(raw,0);
+    }
+  };
+
+  public static class Creator implements ComponentCreator {
+    @Override
+    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      return new WXImage(instance, parent, basicComponentData);
+    }
+  }
+
+  @Deprecated
+  public WXImage(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXImage(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  @Override
+  protected ImageView initComponentHostView(@NonNull Context context) {
+    WXImageView view = new WXImageView(context);
+    view.setScaleType(ScaleType.FIT_XY);
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+      view.setCropToPadding(true);
+    }
+    view.holdComponent(this);
+    return view;
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.RESIZE_MODE:
+        String resizeMode = WXUtils.getString(param, null);
+        if (resizeMode != null) { setResizeMode(resizeMode); }
+        return true;
+      case Constants.Name.RESIZE:
+        String resize = WXUtils.getString(param, null);
+        if (resize != null) { setResize(resize); }
+        return true;
+      case Constants.Name.SRC:
+        String src = WXUtils.getString(param, null);
+        if (src != null) { setSrc(src); }
+        return true;
+      case Constants.Name.IMAGE_QUALITY:
+        return true;
+      case Constants.Name.AUTO_RECYCLE:
+        mAutoRecycle = WXUtils.getBoolean(param, mAutoRecycle);
+        if (!mAutoRecycle && null != getInstance()){
+          getInstance().getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_IMG_UN_RECYCLE_NUM,1);
+        }
+        return true;
+      case Constants.Name.FILTER:
+        int blurRadius = 0;
+        if (param != null && param instanceof String) {
+          blurRadius = parseBlurRadius((String)param);
+        }
+        if (!TextUtils.isEmpty(this.mSrc)) {
+          setBlurRadius(this.mSrc, blurRadius);
+        }
+        return true;
+      default:
+        return super.setProperty(key, param);
+    }
+  }
+
+  @Override
+  public void refreshData(WXComponent component) {
+    super.refreshData(component);
+    if (component instanceof WXImage) {
+      setSrc(component.getAttrs().getImageSrc());
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.RESIZE_MODE)
+  public void setResizeMode(String resizeMode) {
+    (getHostView()).setScaleType(getResizeMode(resizeMode));
+    getHostView().setImageDrawable(getHostView().getDrawable());
+  }
+
+  @RestrictTo(Scope.LIBRARY_GROUP)
+  protected ScaleType getResizeMode(String resizeMode) {
+    ScaleType scaleType = ScaleType.FIT_XY;
+    if (TextUtils.isEmpty(resizeMode)) {
+      return scaleType;
+    }
+
+    switch (resizeMode) {
+      case "cover":
+        scaleType = ScaleType.CENTER_CROP;
+        break;
+      case "contain":
+        scaleType = ScaleType.FIT_CENTER;
+        break;
+      case "stretch":
+        scaleType = ScaleType.FIT_XY;
+        break;
+      default:
+        break;
+    }
+    return scaleType;
+  }
+
+  @WXComponentProp(name = Constants.Name.RESIZE)
+  public void setResize(String resize) {
+    setResizeMode(resize);
+  }
+
+  /**
+   * Process local scheme, load drawable.
+   * @param rewrited
+   */
+  private void setLocalSrc(Uri rewrited) {
+    ImageView imageView;
+    Drawable localDrawable = ImgURIUtil.getDrawableFromLoaclSrc(getContext(), rewrited);
+    if (localDrawable != null && (imageView = getHostView()) != null) {
+      imageView.setImageDrawable(localDrawable);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SRC)
+  public void setSrc(String src) {
+
+    if (getInstance().getImageNetworkHandler() != null) {
+      String localUrl = getInstance().getImageNetworkHandler().fetchLocal(src);
+      if (!TextUtils.isEmpty(localUrl)) {
+        src = localUrl;
+      }
+    }
+
+    if (src == null) {
+      return;
+    }
+
+    ImageView image = getHostView();
+    if("".equals(src) && image != null){
+      image.setImageDrawable(null);
+      return;
+    }
+
+    if(image != null){
+      if(image.getDrawable() != null && !TextUtils.equals(mSrc, src)){
+        image.setImageDrawable(null);
+      }
+    }
+
+
+    this.mSrc = src;
+    WXSDKInstance instance = getInstance();
+    Uri rewrited = instance.rewriteUri(Uri.parse(src), URIAdapter.IMAGE);
+
+    if (Constants.Scheme.LOCAL.equals(rewrited.getScheme())) {
+      setLocalSrc(rewrited);
+    } else {
+      int blur = 0;
+      String blurStr = getStyles().getBlur();
+      blur = parseBlurRadius(blurStr);
+      setRemoteSrc(rewrited, blur);
+    }
+  }
+
+  private void setBlurRadius(@NonNull String src, int blurRadius) {
+    if(getInstance() != null && blurRadius != mBlurRadius) {
+      Uri parsedUri = getInstance().rewriteUri(Uri.parse(src), URIAdapter.IMAGE);
+      if(!Constants.Scheme.LOCAL.equals(parsedUri.getScheme())) {
+        setRemoteSrc(parsedUri,blurRadius);
+      }
+    }
+  }
+
+  private int parseBlurRadius(@Nullable String rawRadius) {
+    if(rawRadius == null) {
+      return 0;
+    }
+    SingleFunctionParser<Integer> parser = new SingleFunctionParser<Integer>(rawRadius,BLUR_RADIUS_MAPPER);
+    List<Integer> list = null;
+    try {
+      list = parser.parse("blur");
+    }catch (Exception e) {
+      return 0;
+    }
+    if(list == null || list.isEmpty()) {
+      return 0;
+    }
+    return list.get(0);
+  }
+
+  @Override
+  public void recycled() {
+    super.recycled();
+
+    if (getInstance().getImgLoaderAdapter() != null) {
+      getInstance().getImgLoaderAdapter().setImage(null, mHost,
+              null, null);
+    } else {
+      if (WXEnvironment.isApkDebugable()) {
+        throw new WXRuntimeException("getImgLoaderAdapter() == null");
+      }
+      WXLogUtils.e("Error getImgLoaderAdapter() == null");
+    }
+  }
+
+  public void autoReleaseImage(){
+    if(mAutoRecycle){
+      if(getHostView() != null){
+        if (getInstance().getImgLoaderAdapter() != null) {
+          getInstance().getImgLoaderAdapter().setImage(null, mHost, null, null);
+        }
+      }
+    }
+  }
+
+  public void autoRecoverImage() {
+    if(mAutoRecycle) {
+      setSrc(mSrc);
+    }
+  }
+
+  private void setRemoteSrc(Uri rewrited, int blurRadius) {
+
+    WXImageStrategy imageStrategy = new WXImageStrategy(getInstanceId());
+    imageStrategy.isClipping = true;
+
+    WXImageSharpen imageSharpen = getAttrs().getImageSharpen();
+    imageStrategy.isSharpen = imageSharpen == WXImageSharpen.SHARPEN;
+
+    imageStrategy.blurRadius = Math.max(0, blurRadius);
+    this.mBlurRadius = blurRadius;
+
+    final String rewritedStr = rewrited.toString();
+    imageStrategy.setImageListener(new MyImageListener(this,rewritedStr));
+
+    String placeholder=null;
+    if(getAttrs().containsKey(Constants.Name.PLACEHOLDER)){
+      placeholder= (String) getAttrs().get(Constants.Name.PLACEHOLDER);
+    }else if(getAttrs().containsKey(Constants.Name.PLACE_HOLDER)){
+      placeholder=(String)getAttrs().get(Constants.Name.PLACE_HOLDER);
+    }
+    if(placeholder!=null){
+      imageStrategy.placeHolder = getInstance().rewriteUri(Uri.parse(placeholder),URIAdapter.IMAGE).toString();
+    }
+
+    imageStrategy.instanceId = getInstanceId();
+    IWXImgLoaderAdapter imgLoaderAdapter = getInstance().getImgLoaderAdapter();
+    if (imgLoaderAdapter != null) {
+      imgLoaderAdapter.setImage(rewritedStr, getHostView(),
+          getImageQuality(), imageStrategy);
+    }
+  }
+
+  @RestrictTo(Scope.LIBRARY_GROUP)
+  protected WXImageQuality getImageQuality(){
+    return getAttrs().getImageQuality();
+  }
+
+  @Override
+  protected void onFinishLayout() {
+    super.onFinishLayout();
+    updateBorderRadius();
+  }
+
+  @Override
+  public void updateProperties(Map<String, Object> props) {
+    super.updateProperties(props);
+    updateBorderRadius();
+  }
+
+  private void updateBorderRadius() {
+    if (getHostView() instanceof WXImageView) {
+      final WXImageView imageView = (WXImageView)getHostView();
+      BorderDrawable borderDrawable = WXViewUtils.getBorderDrawable(getHostView());
+      float[] borderRadius;
+      if (borderDrawable != null) {
+        RectF borderBox = new RectF(0, 0, WXDomUtils.getContentWidth(this), WXDomUtils.getContentHeight(this));
+        borderRadius = borderDrawable.getBorderInnerRadius(borderBox);
+      } else {
+        borderRadius = new float[] {0, 0, 0, 0, 0, 0, 0, 0};
+      }
+      imageView.setBorderRadius(borderRadius);
+
+      if (imageView.getDrawable() instanceof ImageDrawable) {
+        ImageDrawable imageDrawable = (ImageDrawable)imageView.getDrawable();
+        float[] previousRadius = imageDrawable.getCornerRadii();
+        if (!Arrays.equals(previousRadius, borderRadius)) {
+          imageDrawable.setCornerRadii(borderRadius);
+        }
+      }
+    }
+  }
+
+  /**
+   * Need permission {android.permission.WRITE_EXTERNAL_STORAGE}
+   */
+  @JSMethod(uiThread = false)
+  public void save(final JSCallback saveStatuCallback) {
+
+    if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+      if (getContext() instanceof Activity) {
+        ActivityCompat.requestPermissions((Activity) getContext(),
+                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
+      }
+    }
+
+    if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+      if (saveStatuCallback != null) {
+        Map<String, Object> result = new HashMap<>();
+        result.put(SUCCEED, false);
+        result.put(ERRORDESC,"Permission denied: android.permission.WRITE_EXTERNAL_STORAGE");
+        saveStatuCallback.invoke(result);
+      }
+      return;
+    }
+
+    if (mHost == null) {
+      if (saveStatuCallback != null) {
+        Map<String, Object> result = new HashMap<>();
+        result.put(SUCCEED, false);
+        result.put(ERRORDESC,"Image component not initialized");
+        saveStatuCallback.invoke(result);
+      }
+      return;
+    }
+
+    if (mSrc == null || mSrc.equals("")) {
+      if (saveStatuCallback != null) {
+        Map<String, Object> result = new HashMap<>();
+        result.put(SUCCEED, false);
+        result.put(ERRORDESC,"Image does not have the correct src");
+        saveStatuCallback.invoke(result);
+      }
+      return;
+    }
+
+    WXViewToImageUtil.generateImage(mHost, 0, 0xfff8f8f8, new WXViewToImageUtil.OnImageSavedCallback() {
+      @Override
+      public void onSaveSucceed(String path) {
+        if (saveStatuCallback != null) {
+          Map<String, Object> result = new HashMap<>();
+          result.put(SUCCEED, true);
+          saveStatuCallback.invoke(result);
+        }
+      }
+
+      @Override
+      public void onSaveFailed(String errorDesc) {
+        if (saveStatuCallback != null) {
+          Map<String, Object> result = new HashMap<>();
+          result.put(SUCCEED, false);
+          result.put(ERRORDESC,errorDesc);
+          saveStatuCallback.invoke(result);
+        }
+      }
+    });
+  }
+
+  private String preImgUrlStr = "";
+  private void monitorImgSize(ImageView imageView,String currentImgUrlStr){
+    if (null == imageView){
+      return;
+    }
+    WXSDKInstance instance = getInstance();
+    if (null == instance){
+      return;
+    }
+    ViewGroup.LayoutParams params =imageView.getLayoutParams();
+    Drawable img = imageView.getDrawable();
+    if (null == params || null ==img){
+      return;
+    }
+    int imgHeight = img.getIntrinsicHeight();
+    int imgWidth = img.getIntrinsicWidth();
+    if (!preImgUrlStr.equals(currentImgUrlStr)){
+      preImgUrlStr = currentImgUrlStr;
+      if (imgHeight > 1081 && imgWidth > 721){
+        instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_LARGE_IMG_COUNT,1);
+        if (WXAnalyzerDataTransfer.isOpenPerformance){
+          WXAnalyzerDataTransfer.transferPerformance(getInstanceId(),"details",WXInstanceApm.KEY_PAGE_STATS_LARGE_IMG_COUNT,
+              imgWidth+"*"+imgHeight+","+currentImgUrlStr
+              );
+        }
+      }
+      long imgSize = imgHeight * imgWidth;
+      long viewSize = imageView.getMeasuredHeight() * imageView.getMeasuredWidth();
+      if (viewSize == 0){
+          return;
+      }
+      double scaleSize =  imgSize/(double)viewSize;
+      //max diff 40*40
+      if (scaleSize >1.2 && imgSize-viewSize > 1600){
+        instance.getWXPerformance().wrongImgSizeCount++;
+        instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT,1);
+
+        if (WXAnalyzerDataTransfer.isOpenPerformance){
+          WXAnalyzerDataTransfer.transferPerformance(getInstanceId(),"details",WXInstanceApm.KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT,
+              String.format(Locale.ROOT, "imgSize:[%d,%d],viewSize:[%d,%d],urL:%s",imgWidth,imgHeight,imageView.getMeasuredWidth(),imageView.getMeasuredHeight()
+              ,currentImgUrlStr)
+          );
+        }
+      }
+    }
+
+  }
+
+  @Override
+  public void destroy() {
+    if(getHostView() instanceof WXImageView){
+      if (getInstance().getImgLoaderAdapter() != null) {
+        getInstance().getImgLoaderAdapter().setImage(null, mHost, null, null);
+      }
+    }
+    super.destroy();
+  }
+
+  public interface Measurable {
+    int getNaturalWidth();
+    int getNaturalHeight();
+  }
+
+  public  static class MyImageListener implements WXImageStrategy.ImageListener {
+
+    private WeakReference<WXImage> wxImageWeakReference;
+
+    private String rewritedStr;
+
+    MyImageListener(WXImage image,String rewritedStr) {
+      this.wxImageWeakReference = new WeakReference<WXImage>(image);
+      this.rewritedStr = rewritedStr;
+    }
+
+    @Override
+    public void onImageFinish(String url, ImageView imageView, boolean result, Map extra) {
+      WXImage image = wxImageWeakReference.get();
+
+      if(image == null)
+        return;
+
+      if (image.getEvents().contains(Constants.Event.ONLOAD)) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        Map<String, Object> size = new HashMap<>(2);
+        if (imageView != null && imageView instanceof Measurable) {
+          size.put("naturalWidth", ((Measurable) imageView).getNaturalWidth());
+          size.put("naturalHeight", ((Measurable) imageView).getNaturalHeight());
+        } else {
+          size.put("naturalWidth", 0);
+          size.put("naturalHeight", 0);
+        }
+        if (image.containsEvent(Constants.Event.ONLOAD)) {
+          params.put("success", result);
+          params.put("size", size);
+          image.fireEvent(Constants.Event.ONLOAD, params);
+        }
+      }
+      image.monitorImgSize(imageView,rewritedStr);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXIndicator.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXIndicator.java
new file mode 100644
index 0000000..c5688e2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXIndicator.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXCircleIndicator;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+/**
+ *
+ * Slider indicator
+ */
+@Component(lazyload = false)
+public class WXIndicator extends WXComponent<WXCircleIndicator> {
+
+  @Deprecated
+  public WXIndicator(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  public WXIndicator(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+    super(instance, parent, isLazy, basicComponentData);
+  }
+
+  @Override
+  protected void setHostLayoutParams(WXCircleIndicator host, int width, int height, int left, int right, int top, int bottom) {
+      FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
+      this.setMarginsSupportRTL(params, left, top, right, bottom);
+      host.setLayoutParams(params);
+  }
+
+  @Override
+  protected WXCircleIndicator initComponentHostView(@NonNull Context context) {
+    WXCircleIndicator view = new WXCircleIndicator(context);
+    if (getParent() instanceof WXSlider) {
+      return view;
+    } else {
+      if (WXEnvironment.isApkDebugable()) {
+        throw new WXRuntimeException("WXIndicator initView error.");
+      }
+    }
+    return null;
+  }
+
+  @Override
+  protected void onHostViewInitialized(WXCircleIndicator host) {
+    super.onHostViewInitialized(host);
+    if (getParent() instanceof WXSlider) {
+      ((WXSlider) getParent()).addIndicator(this);
+    }
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.ITEM_COLOR:
+        String item_color = WXUtils.getString(param,null);
+        if (item_color != null)
+          setItemColor(item_color);
+        return true;
+      case Constants.Name.ITEM_SELECTED_COLOR:
+        String selected_color = WXUtils.getString(param,null);
+        if (selected_color != null)
+          setItemSelectedColor(selected_color);
+        return true;
+      case Constants.Name.ITEM_SIZE:
+        Integer item_size = WXUtils.getInteger(param,null);
+        if (item_size != null)
+          setItemSize(item_size);
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+
+  @WXComponentProp(name = Constants.Name.ITEM_COLOR)
+  public void setItemColor(String itemColor) {
+    if (!TextUtils.isEmpty(itemColor)) {
+      int colorInt = WXResourceUtils.getColor(itemColor);
+      if (colorInt != Integer.MIN_VALUE) {
+        getHostView().setPageColor(colorInt);
+        getHostView().forceLayout();
+        getHostView().requestLayout();
+      }
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.ITEM_SELECTED_COLOR)
+  public void setItemSelectedColor(String itemSelectedColor) {
+    if (!TextUtils.isEmpty(itemSelectedColor)) {
+      int colorInt = WXResourceUtils.getColor(itemSelectedColor);
+      if (colorInt != Integer.MIN_VALUE) {
+        getHostView().setFillColor(colorInt);
+        getHostView().forceLayout();
+        getHostView().requestLayout();
+      }
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.ITEM_SIZE)
+  public void setItemSize(int itemSize) {
+    if (itemSize < 0) {
+      return;
+    }
+    getHostView().setRadius(WXViewUtils.getRealPxByWidth(itemSize,getInstance().getInstanceViewPortWidth()) / 2.0f);
+    getHostView().forceLayout();
+    getHostView().requestLayout();
+  }
+
+  public void setShowIndicators(boolean show) {
+    if (getHostView() == null) {
+      return;
+    }
+    if (show) {
+      getHostView().setVisibility(View.VISIBLE);
+    } else {
+      getHostView().setVisibility(View.GONE);
+    }
+  }
+
+  // TODO
+//  public static class IndicatorDomNode extends WXDomObject{
+//    public IndicatorDomNode(){
+//      super();
+//    }
+//
+//    @Override
+//    protected Map<String, String> getDefaultStyle() {
+//      WXStyle pendingStyles = getStyles();
+//      Map<String,String> map = new HashMap<>();
+//      if(!pendingStyles.containsKey(Constants.Name.RIGHT))
+//        map.put(Constants.Name.LEFT,"0");
+//      if(!pendingStyles.containsKey(Constants.Name.BOTTOM))
+//        map.put(Constants.Name.TOP,"0");
+//      return map;
+//    }
+//  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXInput.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXInput.java
new file mode 100644
index 0000000..51cc895
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXInput.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXEditText;
+
+/**
+ *
+ * Input component
+ */
+@Component(lazyload = false)
+public class WXInput extends AbstractEditComponent{
+
+  @Deprecated
+  public WXInput(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  public WXInput(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+    super(instance, parent, isLazy, basicComponentData);
+  }
+
+  @Override
+  protected void appleStyleAfterCreated(WXEditText editText) {
+    super.appleStyleAfterCreated(editText);
+    editText.setSingleLine();//default use single line , same to ios
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXLoading.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXLoading.java
new file mode 100644
index 0000000..f83349c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXLoading.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.list.WXListComponent;
+import org.apache.weex.ui.view.WXFrameLayout;
+import org.apache.weex.ui.view.WXLoadingLayout;
+import org.apache.weex.ui.view.refresh.wrapper.BaseBounceView;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.weex.ui.view.refresh.core.WXSwipeLayout.WXOnLoadingListener;
+
+/**
+ * div component
+ */
+@Component(lazyload = false)
+public class WXLoading extends WXBaseRefresh implements WXOnLoadingListener {
+
+  public static final String HIDE = "hide";
+
+  public WXLoading(
+      WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
+    super(instance, parent, lazy, basicComponentData);
+  }
+
+  @Override
+  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
+    return new WXLoadingLayout(context);
+  }
+
+  @Override
+  public void onLoading() {
+    if (getEvents().contains(Constants.Event.ONLOADING)) {
+      fireEvent(Constants.Event.ONLOADING);
+    }
+  }
+
+  @Override
+  protected void setHostLayoutParams(WXFrameLayout host, int width, int height,
+                                     int left, int right, int top, int bottom) {
+    // The view of WXLoading will always be wrapped by a WXRefreshView at some point
+    // which is unknowable for front-end so the margins should always be 0 in LayoutParams,
+    // otherwise it will bring visible layout errors. This means WXLoading do not
+    // support margin.
+    super.setHostLayoutParams(host, width, height, 0, 0, 0, 0);
+  }
+
+  @Override
+  public void onPullingUp(float dy, int pullOutDistance, float viewHeight) {
+    if (getEvents().contains(Constants.Event.ONPULLING_UP)) {
+      Map<String, Object> data = new HashMap<>();
+      data.put(Constants.Name.DISTANCE_Y, dy);
+      data.put(Constants.Name.PULLING_DISTANCE, pullOutDistance);
+      data.put(Constants.Name.VIEW_HEIGHT, viewHeight);
+      fireEvent(Constants.Event.ONPULLING_UP, data);
+    }
+  }
+
+  @Override
+  public boolean canRecycled() {
+    return false;
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.DISPLAY:
+        String display = WXUtils.getString(param,null);
+        if (display != null)
+          setDisplay(display);
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @WXComponentProp(name = Constants.Name.DISPLAY)
+  public void setDisplay(String display) {
+    if (!TextUtils.isEmpty(display)) {
+      if (display.equals(HIDE)) {
+        if (getParent() instanceof WXListComponent || getParent() instanceof WXScroller) {
+          if (((BaseBounceView)getParent().getHostView()).getSwipeLayout().isRefreshing()) {
+            ((BaseBounceView) getParent().getHostView()).finishPullLoad();
+            ((BaseBounceView) getParent().getHostView()).onLoadmoreComplete();
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXLoadingIndicator.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXLoadingIndicator.java
new file mode 100644
index 0000000..25e4682
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXLoadingIndicator.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.graphics.Color;
+
+import android.support.annotation.NonNull;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.refresh.circlebar.CircleProgressBar;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+
+@Component(lazyload = false)
+
+public class WXLoadingIndicator extends WXComponent<CircleProgressBar> {
+
+
+    public WXLoadingIndicator(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+        super(instance, parent, isLazy, basicComponentData);
+    }
+
+    @Override
+    protected CircleProgressBar initComponentHostView(@NonNull Context context) {
+        return new CircleProgressBar(context);
+    }
+
+    @Override
+    protected boolean setProperty(String key, Object param) {
+        switch (key) {
+            case Constants.Name.COLOR:
+                String color = WXUtils.getString(param,null);
+                if (color != null)
+                    setColor(color);
+                return true;
+            case Constants.Name.ANIMATING:
+                Boolean result = WXUtils.getBoolean(param, null);
+                if (result != null) {
+                    setAnimating(result);
+                }
+                return true;
+        }
+        return super.setProperty(key, param);
+    }
+
+    @WXComponentProp(name = Constants.Name.COLOR)
+    public void setColor(String color) {
+        if (color != null && !color.equals("")) {
+            int parseColor = WXResourceUtils.getColor(color, Color.RED);
+            getHostView().setColorSchemeColors(parseColor);
+        }
+    }
+
+    @WXComponentProp(name = Constants.Name.ANIMATING)
+    public void setAnimating(boolean animating) {
+        if (animating) {
+            getHostView().start();
+        } else {
+            getHostView().stop();
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXRefresh.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXRefresh.java
new file mode 100644
index 0000000..7a9cd79
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXRefresh.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.list.WXListComponent;
+import org.apache.weex.ui.view.WXFrameLayout;
+import org.apache.weex.ui.view.WXRefreshLayout;
+import org.apache.weex.ui.view.refresh.wrapper.BaseBounceView;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.weex.ui.view.refresh.core.WXSwipeLayout.WXOnRefreshListener;
+
+/**
+ * div component
+ */
+@Component(lazyload = false)
+public class WXRefresh extends WXBaseRefresh implements WXOnRefreshListener {
+
+  public static final String HIDE = "hide";
+
+  @Deprecated
+  public WXRefresh(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  public WXRefresh(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
+    super(instance, parent, lazy, basicComponentData);
+  }
+
+  @Override
+  protected WXFrameLayout initComponentHostView(@NonNull Context context) {
+    return new WXRefreshLayout(context);
+  }
+
+  @Override
+  public boolean canRecycled() {
+    return false;
+  }
+
+  @Override
+  public void onRefresh() {
+    if(isDestoryed()){
+      return;
+    }
+    
+    if (getEvents().contains(Constants.Event.ONREFRESH)) {
+      fireEvent(Constants.Event.ONREFRESH);
+    }
+  }
+
+  @Override
+  public int getLayoutTopOffsetForSibling() {
+    //offset siblings
+    return getParent() instanceof Scrollable ? -Math.round(getLayoutHeight()) : 0;
+  }
+
+  @Override
+  public void onPullingDown(float dy, int pullOutDistance, float viewHeight) {
+    if (getEvents() != null && getEvents().contains(Constants.Event.ONPULLING_DOWN)) {
+      Map<String, Object> data = new HashMap<>();
+      data.put(Constants.Name.DISTANCE_Y, dy);
+      data.put(Constants.Name.PULLING_DISTANCE, pullOutDistance);
+      data.put(Constants.Name.VIEW_HEIGHT, viewHeight);
+      fireEvent(Constants.Event.ONPULLING_DOWN, data);
+    }
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.DISPLAY:
+        String display = WXUtils.getString(param,null);
+        if (display != null)
+          setDisplay(display);
+        return true;
+    }
+    return super.setProperty(key,param);
+  }
+
+  @WXComponentProp(name = Constants.Name.DISPLAY)
+  public void setDisplay(String display) {
+    if (!TextUtils.isEmpty(display)) {
+      if (display.equals(HIDE)) {
+        if (getParent() instanceof WXListComponent || getParent() instanceof WXScroller) {
+          if (((BaseBounceView)getParent().getHostView()).getSwipeLayout().isRefreshing()) {
+            ((BaseBounceView) getParent().getHostView()).finishPullRefresh();
+            ((BaseBounceView) getParent().getHostView()).onRefreshingComplete();
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXScroller.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXScroller.java
new file mode 100644
index 0000000..52d5c36
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXScroller.java
@@ -0,0 +1,1060 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.v4.view.ViewCompat;
+import android.text.TextUtils;
+import android.view.GestureDetector;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.ICheckBindingScroller;
+import org.apache.weex.common.OnWXScrollListener;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.helper.ScrollStartEndHelper;
+import org.apache.weex.ui.component.helper.WXStickyHelper;
+import org.apache.weex.ui.view.IWXScroller;
+import org.apache.weex.ui.view.WXBaseRefreshLayout;
+import org.apache.weex.ui.view.WXHorizontalScrollView;
+import org.apache.weex.ui.view.WXScrollView;
+import org.apache.weex.ui.view.WXScrollView.WXScrollViewListener;
+import org.apache.weex.ui.view.refresh.wrapper.BaseBounceView;
+import org.apache.weex.ui.view.refresh.wrapper.BounceScrollerView;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Component for scroller. It also support features like
+ * "appear", "disappear" and "sticky"
+ */
+@Component(lazyload = false)
+
+public class WXScroller extends WXVContainer<ViewGroup> implements WXScrollViewListener,Scrollable {
+
+  public static final String DIRECTION = "direction";
+  protected int mOrientation = Constants.Orientation.VERTICAL;
+  private List<WXComponent> mRefreshs=new ArrayList<>();
+  /** Use for offset children layout */
+  private int mChildrenLayoutOffset = 0;
+  private boolean mForceLoadmoreNextTime = false;
+  private int mOffsetAccuracy = 10;
+  private Point mLastReport = new Point(-1, -1);
+  private boolean mHasAddScrollEvent = false;
+  private Boolean mIslastDirectionRTL;
+
+  private static final int SWIPE_MIN_DISTANCE = 5;
+  private static final int SWIPE_THRESHOLD_VELOCITY = 300;
+  private int mActiveFeature = 0;
+  /**
+   * scroll start and scroll end event
+   * */
+  private ScrollStartEndHelper mScrollStartEndHelper;
+
+  private GestureDetector mGestureDetector;
+
+  private int pageSize = 0;
+  private boolean pageEnable = false;
+  private boolean mIsHostAttachedToWindow = false;
+  private View.OnAttachStateChangeListener mOnAttachStateChangeListener;
+
+  private boolean mlastDirectionRTL = false;
+
+  public static class Creator implements ComponentCreator {
+    @Override
+    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      // For performance message collection
+      instance.setUseScroller(true);
+      return new WXScroller(instance, parent, basicComponentData);
+    }
+  }
+  /**
+   * Map for storing appear information
+   **/
+  private Map<String,AppearanceHelper> mAppearanceComponents = new HashMap<>();
+
+  /**
+   * Map for storing component that is sticky.
+   **/
+  private Map<String, Map<String, WXComponent>> mStickyMap = new HashMap<>();
+  private FrameLayout mRealView;
+  private FrameLayout mScrollerView;
+
+  private int mContentHeight = 0;
+  private int mContentWidth = 0;
+
+  private WXStickyHelper stickyHelper;
+  private Handler handler=new Handler(Looper.getMainLooper());
+
+  private boolean isScrollable = true;
+
+  @Deprecated
+  public WXScroller(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXScroller(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+    stickyHelper = new WXStickyHelper(this);
+    instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_SCROLLER_NUM,1);
+  }
+
+  /**
+   * @return FrameLayout inner ScrollView
+   */
+  @Override
+  public ViewGroup getRealView() {
+    return mScrollerView;
+  }
+
+
+  @Override
+  public void createViewImpl() {
+    super.createViewImpl();
+    for (int i = 0; i < mRefreshs.size(); i++) {
+      WXComponent component = mRefreshs.get(i);
+      component.createViewImpl();
+      checkRefreshOrLoading(component);
+    }
+  }
+
+  /**
+   * @return ScrollView
+   */
+  public ViewGroup getInnerView() {
+    if(getHostView() == null) {
+      return null;
+    }
+    if (getHostView() instanceof BounceScrollerView) {
+      return ((BounceScrollerView) getHostView()).getInnerView();
+    } else {
+      return getHostView();
+    }
+  }
+
+  @Override
+  public void addEvent(String type) {
+    super.addEvent(type);
+    if (ScrollStartEndHelper.isScrollEvent(type)
+            && getInnerView() != null && !mHasAddScrollEvent) {
+      mHasAddScrollEvent = true;
+      if (getInnerView() instanceof WXScrollView) {
+        ((WXScrollView) getInnerView()).addScrollViewListener(new WXScrollViewListener() {
+          @Override
+          public void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy) {
+            getScrollStartEndHelper().onScrolled(x, y);
+            if(!getEvents().contains(Constants.Event.SCROLL)){
+              return;
+            }
+            if (shouldReport(x, y)) {
+              fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy);
+            }
+          }
+
+          @Override
+          public void onScrollToBottom(WXScrollView scrollView, int x, int y) {
+            //ignore
+          }
+
+          @Override
+          public void onScrollStopped(WXScrollView scrollView, int x, int y) {
+            //ignore
+          }
+
+          @Override
+          public void onScroll(WXScrollView scrollView, int x, int y) {
+            //ignore
+          }
+        });
+      } else if (getInnerView() instanceof WXHorizontalScrollView) {
+        ((WXHorizontalScrollView) getInnerView()).addScrollViewListener(new WXHorizontalScrollView.ScrollViewListener() {
+          @Override
+          public void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy) {
+            getScrollStartEndHelper().onScrolled(x, y);
+            if(!getEvents().contains(Constants.Event.SCROLL)){
+              return;
+            }
+            if (shouldReport(x, y)) {
+              fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy);
+            }
+          }
+        });
+      }
+    }
+  }
+
+  private void fireScrollEvent(Rect contentFrame, int x, int y, int oldx, int oldy) {
+    fireEvent(Constants.Event.SCROLL, getScrollEvent(x, y));
+  }
+
+  public Map<String, Object> getScrollEvent(int x, int y){
+    Rect contentFrame =  new Rect();
+    if (getInnerView() instanceof WXScrollView) {
+      contentFrame = ((WXScrollView) getInnerView()).getContentFrame();
+    }else if (getInnerView() instanceof WXHorizontalScrollView) {
+      contentFrame = ((WXHorizontalScrollView) getInnerView()).getContentFrame();
+    }
+    Map<String, Object> event = new HashMap<>(2);
+    Map<String, Object> contentSize = new HashMap<>(2);
+    Map<String, Object> contentOffset = new HashMap<>(2);
+
+    int viewport = getInstance().getInstanceViewPortWidth();
+
+    contentSize.put(Constants.Name.WIDTH, WXViewUtils.getWebPxByWidth(contentFrame.width(), viewport));
+    contentSize.put(Constants.Name.HEIGHT, WXViewUtils.getWebPxByWidth(contentFrame.height(), viewport));
+
+    contentOffset.put(Constants.Name.X, -WXViewUtils.getWebPxByWidth(x, viewport));
+    contentOffset.put(Constants.Name.Y, -WXViewUtils.getWebPxByWidth(y, viewport));
+
+    event.put(Constants.Name.CONTENT_SIZE, contentSize);
+    event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
+    return  event;
+  }
+
+  private boolean shouldReport(int x, int y) {
+    if (mLastReport.x == -1 && mLastReport.y == -1) {
+      mLastReport.x = x;
+      mLastReport.y = y;
+      return true;
+    }
+
+    if (mOrientation == Constants.Orientation.HORIZONTAL
+            && Math.abs(x - mLastReport.x) >= mOffsetAccuracy) {
+      mLastReport.x = x;
+      mLastReport.y = y;
+      return true;
+    }
+
+    if (mOrientation == Constants.Orientation.VERTICAL
+            && Math.abs(y - mLastReport.y) >= mOffsetAccuracy) {
+      mLastReport.x = x;
+      mLastReport.y = y;
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   * Intercept refresh view and loading view
+   */
+  @Override
+  public void addSubView(View child, int index) {
+    if (child == null || mRealView == null) {
+      return;
+    }
+
+    if (child instanceof WXBaseRefreshLayout) {
+      return;
+    }
+
+    int count = mRealView.getChildCount();
+    index = index >= count ? -1 : index;
+    if (index == -1) {
+      mRealView.addView(child);
+    } else {
+      mRealView.addView(child, index);
+    }
+  }
+
+  @Override
+  protected int getChildrenLayoutTopOffset() {
+    if (mChildrenLayoutOffset == 0) {
+      // Child LayoutSize data set after call Layout. So init mChildrenLayoutOffset here
+      final int listSize = mRefreshs.size();
+      if (listSize > 0) {
+        for (int i = 0; i < listSize; i++) {
+          WXComponent child = mRefreshs.get(i);
+          mChildrenLayoutOffset += child.getLayoutTopOffsetForSibling();
+        }
+      }
+    }
+    return mChildrenLayoutOffset;
+  }
+
+  /**
+   * Intercept refresh view and loading view
+   */
+  @Override
+  public void addChild(WXComponent child, int index) {
+    if (child instanceof WXBaseRefresh) {
+      if (checkRefreshOrLoading(child)) {
+        mRefreshs.add(child);
+      }
+    }
+    super.addChild(child, index);
+  }
+
+  /**
+   * Setting refresh view and loading view
+   * @param child the refresh_view or loading_view
+   */
+
+  private boolean checkRefreshOrLoading(final WXComponent child) {
+    boolean result = false;
+    if (child instanceof WXRefresh && getHostView() != null) {
+      ((BaseBounceView) getHostView()).setOnRefreshListener((WXRefresh) child);
+      Runnable runnable = WXThread.secure(new Runnable(){
+        @Override
+        public void run() {
+          ((BaseBounceView) getHostView()).setHeaderView(child);
+        }
+      });
+      handler.postDelayed(runnable,100);
+      result = true;
+    }
+
+    if (child instanceof WXLoading && getHostView() !=null) {
+      ((BaseBounceView) getHostView()).setOnLoadingListener((WXLoading)child);
+      Runnable runnable= WXThread.secure(new Runnable(){
+        @Override
+        public void run() {
+          ((BaseBounceView) getHostView()).setFooterView(child);
+        }
+      });
+      handler.postDelayed(runnable, 100);
+      result = true;
+    }
+    return result;
+  }
+
+  @Override
+  public void remove(WXComponent child,boolean destory) {
+    super.remove(child,destory);
+    if(child instanceof WXLoading){
+      ((BaseBounceView)getHostView()).removeFooterView(child);
+    }else if(child instanceof WXRefresh){
+      ((BaseBounceView)getHostView()).removeHeaderView(child);
+    }
+  }
+
+  @Override
+  public void destroy() {
+    super.destroy();
+    if (mAppearanceComponents != null) {
+      mAppearanceComponents.clear();
+    }
+    if (mStickyMap != null) {
+      mStickyMap.clear();
+    }
+    if (mOnAttachStateChangeListener != null && getInnerView() != null) {
+      getInnerView().removeOnAttachStateChangeListener(mOnAttachStateChangeListener);
+    }
+    if (getInnerView() != null && getInnerView() instanceof IWXScroller) {
+      ((IWXScroller) getInnerView()).destroy();
+    }
+  }
+
+  @SuppressLint("RtlHardcoded")
+  @Override
+  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
+    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+      lp.setMargins(left, top, right, bottom);
+      lp.setMarginStart(left);
+      lp.setMarginEnd(right);
+    } else {
+      if (lp instanceof FrameLayout.LayoutParams) {
+        FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
+        if (isLayoutRTL()) {
+          lp_frameLayout.gravity = Gravity.RIGHT | Gravity.TOP;
+          lp.setMargins(right, top, left, bottom);
+        } else {
+          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
+          lp.setMargins(left, top, right, bottom);
+        }
+      } else {
+        lp.setMargins(left, top, right, bottom);
+      }
+    }
+  }
+
+  @Override
+  public void setLayout(WXComponent component) {
+    if (TextUtils.isEmpty(component.getComponentType())
+            || TextUtils.isEmpty(component.getRef()) || component.getLayoutPosition() == null
+            || component.getLayoutSize() == null) {
+      return;
+    }
+    if (component.getHostView() != null) {
+      int layoutDirection = component.isLayoutRTL() ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
+      ViewCompat.setLayoutDirection(component.getHostView(), layoutDirection);
+    }
+    super.setLayout(component);
+  }
+
+  @Override
+  protected MeasureOutput measure(int width, int height) {
+    MeasureOutput measureOutput = new MeasureOutput();
+    if (this.mOrientation == Constants.Orientation.HORIZONTAL) {
+      int screenW = WXViewUtils.getScreenWidth(WXEnvironment.sApplication);
+      int weexW = WXViewUtils.getWeexWidth(getInstanceId());
+      measureOutput.width = width > (weexW >= screenW ? screenW : weexW) ? FrameLayout.LayoutParams.MATCH_PARENT
+              : width;
+      measureOutput.height = height;
+    } else {
+      int screenH = WXViewUtils.getScreenHeight(WXEnvironment.sApplication);
+      int weexH = WXViewUtils.getWeexHeight(getInstanceId());
+      measureOutput.height = height > (weexH >= screenH ? screenH : weexH) ? FrameLayout.LayoutParams.MATCH_PARENT
+              : height;
+      measureOutput.width = width;
+    }
+    return measureOutput;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  protected ViewGroup initComponentHostView(@NonNull Context context) {
+    String scroll;
+    if (getAttrs().isEmpty()) {
+      scroll = "vertical";
+    } else {
+      scroll = getAttrs().getScrollDirection();
+
+      Object o = getAttrs().get(Constants.Name.PAGE_ENABLED);
+
+      pageEnable = o != null && Boolean.parseBoolean(o.toString());
+
+      Object pageSize = getAttrs().get(Constants.Name.PAGE_SIZE);
+      if (pageSize != null) {
+        float aFloat = WXUtils.getFloat(pageSize);
+
+
+        float realPxByWidth = WXViewUtils.getRealPxByWidth(aFloat, getInstance().getInstanceViewPortWidth());
+        if (realPxByWidth != 0) {
+          this.pageSize = (int) realPxByWidth;
+        }
+      }
+
+    }
+
+    ViewGroup host;
+    if(("horizontal").equals(scroll)){
+      mOrientation = Constants.Orientation.HORIZONTAL;
+      final WXHorizontalScrollView scrollView = new WXHorizontalScrollView(context);
+      mRealView = new FrameLayout(context);
+      scrollView.setScrollViewListener(new WXHorizontalScrollView.ScrollViewListener() {
+        @Override
+        public void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy) {
+          procAppear(x,y,oldx,oldy);
+          onLoadMore(scrollView,x,y);
+        }
+      });
+      FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
+              LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+      scrollView.addView(mRealView, layoutParams);
+      scrollView.setHorizontalScrollBarEnabled(false);
+      mScrollerView = scrollView;
+      final WXScroller component = this;
+      final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
+        @Override
+        public void onLayoutChange(View view, final int left, int top, final int right, int bottom, final int oldLeft, int oldTop, final int oldRight, int oldBottom) {
+          final View frameLayout = view;
+          scrollView.post(new Runnable() {
+            @Override
+            public void run() {
+              if (mIslastDirectionRTL != null && isLayoutRTL() != mIslastDirectionRTL) {
+                // when layout direction changed we need convert x to RTL x for scroll to the same item
+                int currentX = getScrollX();
+                int totalWidth = getInnerView().getChildAt(0).getWidth();
+                int displayWidth = getInnerView().getMeasuredWidth();
+                scrollView.scrollTo(totalWidth - currentX - displayWidth, component.getScrollY());
+              } else if (isLayoutRTL()) {
+                // if layout direction not changed, but width changede, we need keep RTL offset
+                int oldWidth = oldRight - oldLeft;
+                int width = right - left;
+                int changedWidth = width - oldWidth;
+                if (changedWidth != 0) {
+                  scrollView.scrollBy(changedWidth, component.getScrollY());
+                }
+              }
+              mIslastDirectionRTL = isLayoutRTL();
+            }
+          });
+        }
+      };
+      mRealView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+        @Override
+        public void onViewAttachedToWindow(View view) {
+          view.addOnLayoutChangeListener(listener);
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View view) {
+          view.removeOnLayoutChangeListener(listener);
+        }
+      });
+
+
+      if(pageEnable) {
+        mGestureDetector = new GestureDetector(new MyGestureDetector(scrollView));
+        scrollView.setOnTouchListener(new View.OnTouchListener() {
+          @Override
+          public boolean onTouch(View v, MotionEvent event) {
+            if (pageSize == 0)  {
+              pageSize = v.getMeasuredWidth();
+            }
+
+            if (mGestureDetector.onTouchEvent(event)) {
+              return true;
+            }
+            else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL ){
+              int scrollX = getScrollX();
+              int featureWidth = pageSize;
+              mActiveFeature = ((scrollX + (featureWidth/2))/featureWidth);
+              int scrollTo = mActiveFeature*featureWidth;
+              scrollView.smoothScrollTo(scrollTo, 0);
+              return true;
+            }
+            else{
+              return false;
+            }
+          }
+        });
+      }
+
+
+      host = scrollView;
+    }else{
+      mOrientation = Constants.Orientation.VERTICAL;
+      BounceScrollerView scrollerView = new BounceScrollerView(context, mOrientation, this);
+      mRealView = new FrameLayout(context);
+      WXScrollView innerView = scrollerView.getInnerView();
+      innerView.addScrollViewListener(this);
+      FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
+              LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+      mScrollerView = innerView;
+      innerView.addView(mRealView, layoutParams);
+      innerView.setVerticalScrollBarEnabled(true);
+      innerView.setNestedScrollingEnabled(WXUtils.getBoolean(getAttrs().get(Constants.Name.NEST_SCROLLING_ENABLED), true));
+      innerView.addScrollViewListener(new WXScrollViewListener() {
+        @Override
+        public void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy) {
+
+        }
+
+        @Override
+        public void onScrollToBottom(WXScrollView scrollView, int x, int y) {
+
+        }
+
+        @Override
+        public void onScrollStopped(WXScrollView scrollView, int x, int y) {
+          List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
+          if(listeners!=null && listeners.size()>0){
+            for (OnWXScrollListener listener : listeners) {
+              if (listener != null) {
+                listener.onScrollStateChanged(scrollView,x,y,OnWXScrollListener.IDLE);
+              }
+            }
+          }
+          getScrollStartEndHelper().onScrollStateChanged(OnWXScrollListener.IDLE);
+        }
+
+        @Override
+        public void onScroll(WXScrollView scrollView, int x, int y) {
+          List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
+          if(listeners!=null && listeners.size()>0){
+            for (OnWXScrollListener listener : listeners) {
+              if (listener != null) {
+                if(listener instanceof ICheckBindingScroller){
+                  if(((ICheckBindingScroller) listener).isNeedScroller(getRef(),null)){
+                    listener.onScrolled(scrollView, x, y);
+                  }
+                }else {
+                  listener.onScrolled(scrollView, x, y);
+                }
+              }
+            }
+          }
+        }
+      });
+      host = scrollerView;
+    }
+
+    host.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+      @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+      @Override
+      public void onGlobalLayout() {
+        procAppear(0,0,0,0);
+        View view;
+        if( (view = getHostView()) == null){
+          return;
+        }
+        if(Build.VERSION.SDK_INT >=  Build.VERSION_CODES.JELLY_BEAN) {
+          view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+        }else{
+          view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+        }
+      }
+    });
+    mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
+      @Override
+      public void onViewAttachedToWindow(View v) {
+        mIsHostAttachedToWindow = true;
+        procAppear(getScrollX(), getScrollY(), getScrollX(), getScrollY());
+      }
+
+      @Override
+      public void onViewDetachedFromWindow(View v) {
+        mIsHostAttachedToWindow = false;
+        dispatchDisappearEvent();
+      }
+    };
+    host.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+    return host;
+  }
+
+  @Override
+  public int getScrollY() {
+    return getInnerView() == null ? 0 : getInnerView().getScrollY();
+  }
+
+  @Override
+  public int getScrollX() {
+    return getInnerView() == null ? 0 : getInnerView().getScrollX();
+  }
+
+  @Override
+  public int getOrientation() {
+    return mOrientation;
+  }
+
+  public Map<String, Map<String, WXComponent>> getStickMap() {
+    return mStickyMap;
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.SHOW_SCROLLBAR:
+        Boolean result = WXUtils.getBoolean(param,null);
+        if (result != null) {
+          setShowScrollbar(result);
+        }
+        return true;
+      case Constants.Name.SCROLLABLE:
+        boolean scrollable = WXUtils.getBoolean(param, true);
+        setScrollable(scrollable);
+        return true;
+      case Constants.Name.OFFSET_ACCURACY:
+        int accuracy = WXUtils.getInteger(param, 10);
+        setOffsetAccuracy(accuracy);
+        return true;
+        default:
+          break;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @WXComponentProp(name = Constants.Name.SHOW_SCROLLBAR)
+  public void setShowScrollbar(boolean show) {
+    if(getInnerView()==null){
+      return;
+    }
+    if (mOrientation == Constants.Orientation.VERTICAL) {
+      getInnerView().setVerticalScrollBarEnabled(show);
+    } else {
+      getInnerView().setHorizontalScrollBarEnabled(show);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SCROLLABLE)
+  public void setScrollable(boolean scrollable) {
+    this.isScrollable = scrollable;
+    View hostView = getInnerView();
+    if(hostView instanceof WXHorizontalScrollView) {
+      ((WXHorizontalScrollView)hostView).setScrollable(scrollable);
+    }else if(hostView instanceof WXScrollView) {
+      ((WXScrollView)hostView).setScrollable(scrollable);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.OFFSET_ACCURACY)
+  public void setOffsetAccuracy(int accuracy) {
+    float realPx = WXViewUtils.getRealPxByWidth(accuracy, getInstance().getInstanceViewPortWidth());
+    this.mOffsetAccuracy = (int) realPx;
+  }
+
+  @Override
+  public boolean isScrollable() {
+    return isScrollable;
+  }
+
+
+  @Override
+  public void bindStickStyle(WXComponent component) {
+    stickyHelper.bindStickStyle(component,mStickyMap);
+  }
+
+  @Override
+  public void unbindStickStyle(WXComponent component) {
+    stickyHelper.unbindStickStyle(component,mStickyMap);
+  }
+
+  /**
+   * Bind appear event
+   */
+  @Override
+  public void bindAppearEvent(WXComponent component) {
+    setWatch(AppearanceHelper.APPEAR,component,true);
+  }
+
+  private void setWatch(int event,WXComponent component,boolean isWatch){
+    AppearanceHelper item = mAppearanceComponents.get(component.getRef());
+    if (item == null) {
+      item = new AppearanceHelper(component);
+      mAppearanceComponents.put(component.getRef(),item);
+    }
+
+    item.setWatchEvent(event,isWatch);
+
+    //check current components appearance status.
+    procAppear(0,0,0,0);
+  }
+
+  /**
+   * Bind disappear event
+   */
+  @Override
+  public void bindDisappearEvent(WXComponent component) {
+    setWatch(AppearanceHelper.DISAPPEAR,component,true);
+  }
+
+  /**
+   * Remove appear event
+   */
+  @Override
+  public void unbindAppearEvent(WXComponent component) {
+    setWatch(AppearanceHelper.APPEAR,component,false);
+  }
+
+  /**
+   * Remove disappear event
+   */
+  @Override
+  public void unbindDisappearEvent(WXComponent component) {
+    setWatch(AppearanceHelper.DISAPPEAR,component,false);
+  }
+
+  @Override
+  public void scrollTo(WXComponent component, Map<String, Object> options) {
+    float offsetFloat = 0;
+    boolean smooth = true;
+
+    if (options != null) {
+      String offset = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
+      smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
+      if (offset != null) {
+        try {
+          offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offset), getInstance().getInstanceViewPortWidth());
+        }catch (Exception e ){
+          WXLogUtils.e("Float parseFloat error :"+e.getMessage());
+        }
+      }
+    }
+
+    if(pageEnable) {
+      mActiveFeature = mChildren.indexOf(component);
+    }
+
+    int viewYInScroller = component.getAbsoluteY() - getAbsoluteY();
+    int viewXInScroller = 0;
+    if (this.isLayoutRTL()) {
+      // if layout direction is rtl, we need calculate rtl scroll x;
+      if (component.getParent() != null && component.getParent() == this) {
+        if (getInnerView().getChildCount() > 0) {
+          int totalWidth = getInnerView().getChildAt(0).getWidth();
+          int displayWidth = getInnerView().getMeasuredWidth();
+          viewXInScroller = totalWidth - (component.getAbsoluteX() - getAbsoluteX()) - displayWidth;
+        } else {
+          viewXInScroller = component.getAbsoluteX() - getAbsoluteX();
+        }
+      } else {
+        int displayWidth = getInnerView().getMeasuredWidth();
+        viewXInScroller = component.getAbsoluteX() - getAbsoluteX() - displayWidth + (int)component.getLayoutWidth();
+      }
+      offsetFloat = -offsetFloat;
+    } else {
+      viewXInScroller = component.getAbsoluteX() - getAbsoluteX();
+    }
+    scrollBy(viewXInScroller - getScrollX() + (int) offsetFloat, viewYInScroller - getScrollY() + (int) offsetFloat, smooth);
+
+  }
+
+  /**
+   * Scroll by specified distance. Horizontal scroll is not supported now.
+   * @param x horizontal distance, not support
+   * @param y vertical distance. Negative for scroll to top
+   */
+  public void scrollBy(final int x, final int y) {
+    scrollBy(x, y, false);
+  }
+
+  public void scrollBy(final int x, final int y, final boolean smooth) {
+    if (getInnerView() == null) {
+      return;
+    }
+
+    getInnerView().postDelayed(new Runnable() {
+      @Override
+      public void run() {
+        if (mOrientation == Constants.Orientation.VERTICAL) {
+          if (smooth) {
+            ((WXScrollView) getInnerView()).smoothScrollBy(0, y);
+          } else {
+            ((WXScrollView) getInnerView()).scrollBy(0, y);
+          }
+        } else {
+          if (smooth) {
+            ((WXHorizontalScrollView) getInnerView()).smoothScrollBy(x, 0);
+          } else {
+            ((WXHorizontalScrollView) getInnerView()).scrollBy(x, 0);
+          }
+        }
+        getInnerView().invalidate();
+      }
+    }, 16);
+  }
+
+  @Override
+  public void onScrollChanged(WXScrollView scrollView, int x, int y,
+                              int oldx, int oldy) {
+    procAppear( x, y, oldx, oldy);
+  }
+
+  @Override
+  public void notifyAppearStateChange(String wxEventType, String direction) {
+    if (containsEvent(Constants.Event.APPEAR) || containsEvent(Constants.Event.DISAPPEAR)) {
+      Map<String, Object> params = new HashMap<>();
+      params.put("direction", direction);
+      fireEvent(wxEventType, params);
+    }
+    // No-op. The moment to notify children is decided by the time when scroller is attached
+    // or detached to window. Do not call super as scrollview has different disposal.
+  }
+
+  /**
+   * Process event like appear and disappear
+   *
+   * This method will be invoked in several situation below.
+   *    1. bind or unbind event
+   *    2. host view is attached to window
+   *    3. when scrollview is scrolling
+   */
+  private void procAppear(int x, int y, int oldx,
+                          int oldy) {
+    if (!mIsHostAttachedToWindow) return;
+    int moveY = y - oldy;
+    int moveX = x - oldx;
+    String direction = moveY > 0 ? Constants.Value.DIRECTION_UP :
+            moveY < 0 ? Constants.Value.DIRECTION_DOWN : null;
+    if (mOrientation == Constants.Orientation.HORIZONTAL && moveX != 0) {
+      direction = moveX > 0 ? Constants.Value.DIRECTION_RIGHT : Constants.Value.DIRECTION_LEFT;
+    }
+
+    for (Entry<String, AppearanceHelper> item : mAppearanceComponents.entrySet()) {
+      AppearanceHelper helper = item.getValue();
+
+      if (!helper.isWatch()) {
+        continue;
+      }
+      boolean visible = checkItemVisibleInScroller(helper.getAwareChild());
+
+      int result = helper.setAppearStatus(visible);
+      if (result != AppearanceHelper.RESULT_NO_CHANGE) {
+        helper.getAwareChild().notifyAppearStateChange(result == AppearanceHelper.RESULT_APPEAR ? Constants.Event.APPEAR : Constants.Event.DISAPPEAR, direction);
+      }
+    }
+  }
+
+  /**
+   * Check the view of given component is visible in scrollview.
+   *
+   * @param component ready to be check
+   * @return item is visible
+   */
+  private boolean checkItemVisibleInScroller(WXComponent component) {
+    boolean visible = false;
+    while (component != null && !(component instanceof WXScroller)) {
+      if (component.getParent() instanceof WXScroller) {
+        if (mOrientation == Constants.Orientation.HORIZONTAL) {
+          int offsetLeft = (int) component.getLayoutPosition().getLeft() - getScrollX();
+          visible = (offsetLeft > 0 - component.getLayoutWidth() && offsetLeft < getLayoutWidth());
+        } else {
+          int offsetTop = (int) component.getLayoutPosition().getTop() - getScrollY();
+          visible = (offsetTop > 0 - component.getLayoutHeight() && offsetTop < getLayoutHeight());
+        }
+      }
+      component = component.getParent();
+    }
+    return visible;
+  }
+
+  /**
+   * Dispatch disappear event to the child components in need.
+   */
+  private void dispatchDisappearEvent() {
+    for (Entry<String, AppearanceHelper> item : mAppearanceComponents.entrySet()) {
+      AppearanceHelper helper = item.getValue();
+      if (!helper.isWatch()) {
+        continue;
+      }
+      int result = helper.setAppearStatus(false);
+      if (result != AppearanceHelper.RESULT_NO_CHANGE) {
+        helper.getAwareChild().notifyAppearStateChange(result == AppearanceHelper.RESULT_APPEAR ?
+                Constants.Event.APPEAR : Constants.Event.DISAPPEAR, "");
+      }
+    }
+  }
+
+  @Override
+  public void onScrollToBottom(WXScrollView scrollView, int x, int y) {
+
+  }
+
+  @Override
+  public void onScrollStopped(WXScrollView scrollView, int x, int y) {
+  }
+
+  @Override
+  public void onScroll(WXScrollView scrollView, int x, int y) {
+
+    this.onLoadMore(scrollView, x, y);
+  }
+
+  /**
+   * Handle loadMore Event.when Scroller has bind loadMore Event and set the attr of loadMoreOffset
+   * it will tell the JS to handle the event of onLoadMore;
+   * @param scrollView  the WXScrollView
+   * @param x the X direction
+   * @param y the Y direction
+   */
+  protected void onLoadMore(FrameLayout scrollView, int x, int y) {
+    try {
+      String offset = getAttrs().getLoadMoreOffset();
+      if (TextUtils.isEmpty(offset)) {
+        return;
+      }
+      int offsetInt = (int)WXViewUtils.getRealPxByWidth(Float.parseFloat(offset), getInstance().getInstanceViewPortWidth());
+
+      if (scrollView instanceof WXHorizontalScrollView){
+        int contentWidth = scrollView.getChildAt(0).getWidth();
+        int offScreenX =  contentWidth-x-scrollView.getWidth();
+        if (offScreenX < offsetInt && (mContentWidth != contentWidth || mForceLoadmoreNextTime)){
+          fireEvent(Constants.Event.LOADMORE);
+          mContentWidth=contentWidth;
+          mForceLoadmoreNextTime = false;
+        }
+      }else {
+        int contentH = scrollView.getChildAt(0).getHeight();
+        int scrollerH = scrollView.getHeight();
+        int offScreenY = contentH - y - scrollerH;
+        if (offScreenY < offsetInt) {
+          if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d("[WXScroller-onScroll] offScreenY :" + offScreenY);
+          }
+          if (mContentHeight != contentH || mForceLoadmoreNextTime) {
+            fireEvent(Constants.Event.LOADMORE);
+            mContentHeight = contentH;
+            mForceLoadmoreNextTime = false;
+          }
+        }
+      }
+    } catch (Exception e) {
+      WXLogUtils.d("[WXScroller-onScroll] ", e);
+    }
+
+  }
+
+  @JSMethod
+  public void resetLoadmore() {
+    mForceLoadmoreNextTime = true;
+  }
+
+  public ScrollStartEndHelper getScrollStartEndHelper() {
+    if(mScrollStartEndHelper == null){
+      mScrollStartEndHelper = new ScrollStartEndHelper(this);
+    }
+    return mScrollStartEndHelper;
+  }
+
+
+  class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
+    public WXHorizontalScrollView getScrollView() {
+      return scrollView;
+    }
+
+    private final WXHorizontalScrollView scrollView;
+
+    MyGestureDetector(WXHorizontalScrollView horizontalScrollView) {
+      scrollView = horizontalScrollView;
+    }
+
+    @Override
+    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+      int mItems = mChildren.size();
+      try {
+        //right to left
+        if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+          int featureWidth = pageSize;
+          mActiveFeature = (mActiveFeature < (mItems - 1))? mActiveFeature + 1:mItems -1;
+          scrollView.smoothScrollTo(mActiveFeature*featureWidth, 0);
+          return true;
+        }
+        //left to right
+        else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+          int featureWidth = pageSize;
+          mActiveFeature = (mActiveFeature > 0)? mActiveFeature - 1:0;
+          scrollView.smoothScrollTo(mActiveFeature*featureWidth, 0);
+          return true;
+        }
+      } catch (Exception e) {
+        WXLogUtils.e("There was an error processing the Fling event:" + e.getMessage());
+      }
+      return false;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXSlider.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXSlider.java
new file mode 100644
index 0000000..9459f87
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXSlider.java
@@ -0,0 +1,619 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v4.view.ViewPager;
+import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.text.TextUtils;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.BaseFrameLayout;
+import org.apache.weex.ui.view.WXCircleIndicator;
+import org.apache.weex.ui.view.WXCirclePageAdapter;
+import org.apache.weex.ui.view.WXCircleViewPager;
+import org.apache.weex.ui.view.gesture.WXGestureType;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component(lazyload = false)
+
+public class WXSlider extends WXVContainer<FrameLayout> {
+
+  public static final String INDEX = "index";
+  public static final String INFINITE = "infinite";
+
+  private boolean isInfinite = true;
+
+  Map<String, Object> params = new HashMap<>();
+  private float offsetXAccuracy = 0.1f;
+  private int initIndex = -1;
+  private boolean keepIndex = false;
+  private Runnable initRunnable;
+
+
+  public static class Creator implements ComponentCreator {
+    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      return new WXSlider(instance, parent, basicComponentData);
+    }
+  }
+
+  /**
+   * Scrollable sliderview
+   */
+  /**
+   * package
+   **/
+  WXCircleViewPager mViewPager;
+  /**
+   * Circle indicator
+   */
+  protected WXIndicator mIndicator;
+
+  /**
+   * Adapter for sliderview
+   */
+  protected WXCirclePageAdapter mAdapter;
+
+  protected boolean mShowIndicators = true;
+
+  protected OnPageChangeListener mPageChangeListener = new SliderPageChangeListener();
+
+  @Deprecated
+  public WXSlider(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXSlider(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  @Override
+  protected BaseFrameLayout initComponentHostView(@NonNull Context context) {
+    BaseFrameLayout view = new BaseFrameLayout(context);
+    // init view pager
+    if (getAttrs() != null) {
+      Object obj = getAttrs().get(INFINITE);
+      isInfinite = WXUtils.getBoolean(obj, true);
+    }
+    FrameLayout.LayoutParams pagerParams = new FrameLayout.LayoutParams(
+        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    mViewPager = new WXCircleViewPager(context);
+    mViewPager.setCircle(isInfinite);
+    mViewPager.setLayoutParams(pagerParams);
+
+    // init adapter
+    mAdapter = new WXCirclePageAdapter(isInfinite);
+    mViewPager.setAdapter(mAdapter);
+    // add to parent
+    view.addView(mViewPager);
+    mViewPager.addOnPageChangeListener(mPageChangeListener);
+
+    registerActivityStateListener();
+
+    return view;
+  }
+
+  /**
+   * Slider is not a regular container,top/left/right/bottom not apply to view,expect indicator.
+   */
+  @Override
+  public LayoutParams getChildLayoutParams(WXComponent child,View childView, int width, int height, int left, int right, int top, int bottom) {
+    ViewGroup.LayoutParams lp = childView.getLayoutParams();
+    if (lp == null) {
+      lp = new FrameLayout.LayoutParams(width, height);
+    } else {
+      lp.width = width;
+      lp.height = height;
+    }
+
+    if (lp instanceof ViewGroup.MarginLayoutParams) {
+      //expect indicator .
+      if (child instanceof WXIndicator) {
+        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, left, top, right, bottom);
+      } else {
+        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, 0, 0, 0, 0);
+      }
+    }
+    return lp;
+  }
+
+
+  @Override
+  public void addEvent(String type) {
+    super.addEvent(type);
+    if (Constants.Event.SCROLL.equals(type)) {
+      if (mViewPager == null) {
+        return;
+      }
+      mViewPager.addOnPageChangeListener(new SliderOnScrollListener(this));
+    }
+  }
+
+  @Override
+  public boolean containsGesture(WXGestureType WXGestureType) {
+    //Enable gesture for slider
+    return super.containsGesture(WXGestureType);
+  }
+
+  @Override
+  public ViewGroup getRealView() {
+    return mViewPager;
+  }
+
+  @Override
+  public void addSubView(View view, int index) {
+    if (view == null || mAdapter == null) {
+      return;
+    }
+
+    if (view instanceof WXCircleIndicator) {
+      return;
+    }
+    mAdapter.addPageView(view);
+    hackTwoItemsInfiniteScroll();
+    if (initIndex != -1 && mAdapter.getRealCount() > initIndex) {
+      if(initRunnable == null){
+        initRunnable = new Runnable() {
+          @Override
+          public void run() {
+            initIndex = getInitIndex();
+            mViewPager.setCurrentItem(getRealIndex(initIndex));
+            initIndex = -1;
+            initRunnable = null;
+          }
+        };
+      }
+      mViewPager.removeCallbacks(initRunnable);
+      mViewPager.postDelayed(initRunnable, 50);
+    } else {
+      if (!keepIndex) {
+        mViewPager.setCurrentItem(getRealIndex(0));
+      }
+    }
+    if (mIndicator != null) {
+      mIndicator.getHostView().forceLayout();
+      mIndicator.getHostView().requestLayout();
+    }
+  }
+
+  @Override
+  public void setLayout(WXComponent component) {
+    if (mAdapter != null) {
+      mAdapter.setLayoutDirectionRTL(this.isLayoutRTL());
+    }
+    super.setLayout(component);
+  }
+
+  @Override
+  public void remove(WXComponent child, boolean destroy) {
+    if (child == null || child.getHostView() == null || mAdapter == null) {
+      return;
+    }
+
+    mAdapter.removePageView(child.getHostView());
+    hackTwoItemsInfiniteScroll();
+    super.remove(child,destroy);
+  }
+
+  @Override
+  public void destroy() {
+    super.destroy();
+    if (mViewPager != null) {
+      mViewPager.stopAutoScroll();
+      mViewPager.removeAllViews();
+      mViewPager.destory();
+    }
+  }
+
+  @Override
+  public void onActivityResume() {
+    super.onActivityResume();
+    if (mViewPager != null && mViewPager.isAutoScroll()) {
+      mViewPager.startAutoScroll();
+    }
+  }
+
+  @Override
+  public void onActivityStop() {
+    super.onActivityStop();
+    if (mViewPager != null) {
+      mViewPager.pauseAutoScroll();
+    }
+  }
+
+  public void addIndicator(WXIndicator indicator) {
+    FrameLayout root = getHostView();
+    if (root == null) {
+      return;
+    }
+    mIndicator = indicator;
+    mIndicator.setShowIndicators(mShowIndicators);
+    WXCircleIndicator indicatorView = indicator.getHostView();
+    if (indicatorView != null) {
+      indicatorView.setCircleViewPager(mViewPager);
+      // indicatorView.setOnPageChangeListener(mPageChangeListener);  // commented for twice onChange() called when do slide.
+      root.addView(indicatorView);
+    }
+
+  }
+
+
+  private int getInitIndex(){
+    Object index = getAttrs().get(Constants.Name.INDEX);
+    int select = WXUtils.getInteger(index, initIndex);
+    if(mAdapter == null || mAdapter.getCount() == 0){
+      return  0;
+    }
+    if(select >= mAdapter.getRealCount()){
+      select = select%mAdapter.getRealCount();
+    }
+
+    return select;
+  }
+
+  private int getRealIndex(int idx) {
+    int retIdx = idx;
+
+    if (mAdapter.getRealCount() > 0) {
+      if(idx >= mAdapter.getRealCount()) retIdx = mAdapter.getRealCount() - 1;
+      if (isLayoutRTL()) {
+        retIdx = mAdapter.getRealCount() - 1 - retIdx;
+      }
+    }
+    retIdx = retIdx + 0;
+    return retIdx;
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.VALUE:
+        String value = WXUtils.getString(param, null);
+        if (value != null) {
+          setValue(value);
+        }
+        return true;
+      case Constants.Name.AUTO_PLAY:
+        String aotu_play = WXUtils.getString(param, null);
+        if (aotu_play != null) {
+          setAutoPlay(aotu_play);
+        }
+        return true;
+      case Constants.Name.SHOW_INDICATORS:
+        String indicators = WXUtils.getString(param, null);
+        if (indicators != null) {
+          setShowIndicators(indicators);
+        }
+        return true;
+      case Constants.Name.INTERVAL:
+        Integer interval = WXUtils.getInteger(param, null);
+        if (interval != null) {
+          setInterval(interval);
+        }
+        return true;
+      case Constants.Name.INDEX:
+        Integer index = WXUtils.getInteger(param, null);
+        if (index != null) {
+          setIndex(index);
+        }
+        return true;
+      case Constants.Name.OFFSET_X_ACCURACY:
+        Float accuracy = WXUtils.getFloat(param, 0.1f);
+        if (accuracy != 0) {
+          setOffsetXAccuracy(accuracy);
+        }
+        return true;
+      case Constants.Name.SCROLLABLE:
+        boolean scrollable = WXUtils.getBoolean(param, true);
+        setScrollable(scrollable);
+        return true;
+      case Constants.Name.KEEP_INDEX:
+        this.keepIndex = WXUtils.getBoolean(param, false);
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @Deprecated
+  @WXComponentProp(name = Constants.Name.VALUE)
+  public void setValue(String value) {
+    if (value == null || getHostView() == null) {
+      return;
+    }
+    int i;
+    try {
+      i = Integer.parseInt(value);
+    } catch (NumberFormatException e) {
+      WXLogUtils.e("", e);
+      return;
+    }
+
+    setIndex(i);
+  }
+
+  @WXComponentProp(name = Constants.Name.AUTO_PLAY)
+  public void setAutoPlay(String autoPlay) {
+    if (TextUtils.isEmpty(autoPlay) || autoPlay.equals("false")) {
+      mViewPager.stopAutoScroll();
+    } else {
+      mViewPager.stopAutoScroll();
+      mViewPager.startAutoScroll();
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SHOW_INDICATORS)
+  public void setShowIndicators(String show) {
+    if (TextUtils.isEmpty(show) || show.equals("false")) {
+      mShowIndicators = false;
+    } else {
+      mShowIndicators = true;
+    }
+
+    if (mIndicator == null) {
+      return;
+    }
+    mIndicator.setShowIndicators(mShowIndicators);
+  }
+
+  @WXComponentProp(name = Constants.Name.INTERVAL)
+  public void setInterval(int intervalMS) {
+    if (mViewPager != null && intervalMS > 0) {
+      mViewPager.setIntervalTime(intervalMS);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.INDEX)
+  public void setIndex(int index) {
+    if (mViewPager != null && mAdapter != null) {
+      if (index >= mAdapter.getRealCount() || index < 0) {
+        initIndex = index;
+        return;
+      }
+
+      index = getRealIndex(index);
+      mViewPager.setCurrentItem(index);
+      if (mIndicator != null && mIndicator.getHostView() != null
+              && mIndicator.getHostView().getRealCurrentItem() != index) {
+        //OnPageChangeListener not triggered
+        WXLogUtils.d("setIndex >>>> correction indicator to " + index);
+        mIndicator.getHostView().setRealCurrentItem(index);
+        mIndicator.getHostView().invalidate();
+
+        if (mPageChangeListener != null && mAdapter != null) {
+          mPageChangeListener.onPageSelected(mAdapter.getFirst() + index);
+        }
+      }
+    }
+  }
+  @WXComponentProp(name = Constants.Name.SCROLLABLE)
+  public void setScrollable(boolean scrollable) {
+    if (mViewPager != null && mAdapter != null) {
+      mViewPager.setScrollable(scrollable);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.OFFSET_X_ACCURACY)
+  public void setOffsetXAccuracy(float accuracy) {
+    this.offsetXAccuracy = accuracy;
+  }
+
+  protected class SliderPageChangeListener implements OnPageChangeListener {
+
+    private int lastPos = -1;
+
+    @Override
+    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+    }
+
+    @Override
+    public void onPageSelected(int pos) {
+      if (mAdapter.getRealPosition(pos) == lastPos) {
+        return;
+      }
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d("onPageSelected >>>>" + mAdapter.getRealPosition(pos) + " lastPos: " + lastPos);
+      }
+      if (mAdapter == null || mAdapter.getRealCount() == 0) {
+        return;
+      }
+
+      int realPosition = mAdapter.getRealPosition(pos);
+      if (mChildren == null || realPosition >= mChildren.size()) {
+        return;
+      }
+
+      if (getEvents().size() == 0) {
+        return;
+      }
+      WXEvent event = getEvents();
+      String ref = getRef();
+      if (event.contains(Constants.Event.CHANGE) && WXViewUtils.onScreenArea(getHostView())) {
+        params.put(INDEX, realPosition);
+
+        Map<String, Object> domChanges = new HashMap<>();
+        Map<String, Object> attrsChanges = new HashMap<>();
+        attrsChanges.put(INDEX, realPosition);
+        domChanges.put("attrs", attrsChanges);
+        WXSDKManager.getInstance().fireEvent(getInstanceId(), ref,
+            Constants.Event.CHANGE, params, domChanges);
+      }
+
+      mViewPager.requestLayout();
+      getHostView().invalidate();
+      lastPos = mAdapter.getRealPosition(pos);
+    }
+
+    @Override
+    public void onPageScrollStateChanged(int arg0) {
+      FrameLayout root = getHostView();
+      if (null != root) {
+        root.invalidate();
+      }
+    }
+  }
+
+  protected static class SliderOnScrollListener implements OnPageChangeListener {
+    private float lastPositionOffset = 99f;
+    private int selectedPosition;
+    private WXSlider target;
+
+    public SliderOnScrollListener(WXSlider target) {
+      this.target = target;
+      this.selectedPosition = target.mViewPager.superGetCurrentItem();
+    }
+
+    @Override
+    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+      if (lastPositionOffset == 99f) {
+        lastPositionOffset = positionOffset;
+        return;
+      }
+
+      float offset = positionOffset - lastPositionOffset;
+
+      if (Math.abs(offset) >= target.offsetXAccuracy) {
+        if (position == selectedPosition) {
+          //slide to left. positionOffset[0 -> 1]
+          Map<String,Object> event = new HashMap<>(1);
+          event.put(Constants.Name.OFFSET_X_RATIO, -positionOffset);
+          target.fireEvent(Constants.Event.SCROLL, event);
+        } else if (position < selectedPosition) {
+          //slide to right. positionOffset[1 -> 0]
+          Map<String,Object> event = new HashMap<>(1);
+          event.put(Constants.Name.OFFSET_X_RATIO, (1f - positionOffset));
+          target.fireEvent(Constants.Event.SCROLL, event);
+        }
+        lastPositionOffset = positionOffset;
+      }
+    }
+
+    @Override
+    public void onPageSelected(int position) {
+      selectedPosition = position;
+    }
+
+    @Override
+    public void onPageScrollStateChanged(int state) {
+
+      /**
+       * @homeblog@vip.qq.com
+       *
+       *  add scrollstart & scrollend event
+       *
+       */
+      switch (state) {
+        case ViewPager.SCROLL_STATE_IDLE:
+          lastPositionOffset = 99f;
+          target.fireEvent("scrollend");
+          break;
+        case ViewPager.SCROLL_STATE_DRAGGING:
+          target.fireEvent("scrollstart");
+          break;
+        case ViewPager.SCROLL_STATE_SETTLING:
+          break;
+
+      }
+    }
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  private void hackTwoItemsInfiniteScroll() {
+    if (mViewPager == null || mAdapter == null) {
+      return;
+    }
+    if (isInfinite) {
+      if (mAdapter.getRealCount() == 2) {
+        final GestureDetector gestureDetector = new GestureDetector(getContext(), new FlingGestureListener(mViewPager));
+        mViewPager.setOnTouchListener(new View.OnTouchListener() {
+          @Override
+          public boolean onTouch(View v, MotionEvent event) {
+            return gestureDetector.onTouchEvent(event);
+          }
+        });
+      } else {
+        mViewPager.setOnTouchListener(null);
+      }
+    }
+  }
+
+  private static class FlingGestureListener extends GestureDetector.SimpleOnGestureListener {
+    private static final int SWIPE_MIN_DISTANCE = WXViewUtils.dip2px(50);
+    private static final int SWIPE_MAX_OFF_PATH = WXViewUtils.dip2px(250);
+    private static final int SWIPE_THRESHOLD_VELOCITY = WXViewUtils.dip2px(200);
+    private WeakReference<WXCircleViewPager> pagerRef;
+
+    FlingGestureListener(WXCircleViewPager pager) {
+      this.pagerRef = new WeakReference<>(pager);
+    }
+
+    @Override
+    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+      WXCircleViewPager mViewPager = pagerRef.get();
+      if (mViewPager == null) {
+        return false;
+      }
+
+      try {
+        if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
+          return false;
+        }
+
+        if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
+                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
+                && mViewPager.superGetCurrentItem() == 1) {
+          // right to left swipe
+          mViewPager.setCurrentItem(0, false);
+          return true;
+        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
+                && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
+                && mViewPager.superGetCurrentItem() == 0) {
+          // left to right swipe
+          mViewPager.setCurrentItem(1, false);
+          return true;
+        }
+      } catch (Exception e) {
+        // ignore
+      }
+      return false;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXSliderNeighbor.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXSliderNeighbor.java
new file mode 100644
index 0000000..cfd7d0b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXSliderNeighbor.java
@@ -0,0 +1,413 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v4.view.ViewPager;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.BaseFrameLayout;
+import org.apache.weex.ui.view.WXCircleIndicator;
+import org.apache.weex.ui.view.WXCirclePageAdapter;
+import org.apache.weex.ui.view.WXCircleViewPager;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+/**
+ * Known Issus: In auto play mode, neighbor view not scaled or aplhaed rarely.
+ *
+ * Created by xingjiu on 16/8/18.
+ */
+public class WXSliderNeighbor extends WXSlider {
+    public static final String NEIGHBOR_SCALE = "neighborScale"; // the init scale of neighbor page
+    public static final String NEIGHBOR_ALPHA = "neighborAlpha"; // the init alpha of neighbor page
+    public static final String NEIGHBOR_SPACE = "neighborSpace"; // the init space of neighbor page
+    public static final String CURRENT_ITEM_SCALE = "currentItemScale"; // the scale of middle item
+
+    private static final int DEFAULT_NEIGHBOR_SPACE = 25;
+    private static final float DEFAULT_NEIGHBOR_SCALE = 0.8F;
+    private static final float DEFAULT_NEIGHBOR_ALPHA = 0.6F;
+    private static final float DEFAULT_CURRENT_ITEM_SCALE = 0.9F;
+
+    private float mNeighborScale = DEFAULT_NEIGHBOR_SCALE;
+    private float mNeighborAlpha = DEFAULT_NEIGHBOR_ALPHA;
+    private float mNeighborSpace = DEFAULT_NEIGHBOR_SPACE;
+    private float mCurrentItemScale = DEFAULT_CURRENT_ITEM_SCALE;
+
+    private ZoomTransformer mCachedTransformer;
+
+    public WXSliderNeighbor(
+        WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+        super(instance, parent, basicComponentData);
+    }
+
+    public static class Creator implements ComponentCreator {
+        public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+            return new WXSliderNeighbor(instance, parent, basicComponentData);
+        }
+    }
+
+    @Override
+    public void bindData(WXComponent component) {
+        super.bindData(component);
+    }
+
+    @Override
+    protected BaseFrameLayout initComponentHostView(@NonNull Context context) {
+        BaseFrameLayout view = new BaseFrameLayout(context);
+
+        // init view pager
+        FrameLayout.LayoutParams pagerParams = new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
+        pagerParams.gravity = Gravity.CENTER;
+        mViewPager = new WXCircleViewPager(getContext());
+        mViewPager.setLayoutParams(pagerParams);
+
+        // init adapter
+        mAdapter = new WXCirclePageAdapter();
+        mViewPager.setAdapter(mAdapter);
+
+        // add to parent
+        view.addView(mViewPager);
+        mViewPager.addOnPageChangeListener(mPageChangeListener);
+
+        mViewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
+        registerActivityStateListener();
+
+        mViewPager.setPageTransformer(false, createTransformer());
+
+        return view;
+    }
+
+    ZoomTransformer createTransformer() {
+        if(mCachedTransformer == null) {
+            mCachedTransformer = new ZoomTransformer();
+        }
+        return mCachedTransformer;
+    }
+
+    @Override
+    public void addSubView(View view, final int index) {
+        if (view == null || mAdapter == null) {
+            return;
+        }
+
+        if (view instanceof WXCircleIndicator) {
+            return;
+        }
+
+        FrameLayout wrapper = new FrameLayout(getContext());
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        params.gravity = Gravity.CENTER;
+        view.setLayoutParams(params);
+        wrapper.addView(view);
+        super.addSubView(wrapper,index);
+
+        updateAdapterScaleAndAlpha(mNeighborAlpha, mNeighborScale); // we need to set neighbor view status when added.
+
+        mViewPager.postDelayed(WXThread.secure(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if(mViewPager.getRealCount() > 0 && index > 2) { // index > 2 mean more than two times, then need a fake drag
+                        // prevent a bug of init status. ZoomTransformer no called as excepted.
+                        mViewPager.beginFakeDrag();
+                        mViewPager.fakeDragBy(1); // must be 1
+                    }
+                }catch (IndexOutOfBoundsException e){
+                    // do nothing
+                } finally {
+                    try {
+                        mViewPager.endFakeDrag();
+                    }catch (Exception e) {
+                        // do nothing
+                    }
+                }
+            }
+        }), 50);
+    }
+
+    private void updateScaleAndAlpha(View view, float alpha, float scale) {
+        if(null == view) {
+            return;
+        }
+        if(alpha >= 0 && view.getAlpha() != alpha) {
+            view.setAlpha(alpha);
+        }
+        if(scale >= 0 && view.getScaleX() != scale) {
+            view.setScaleX(scale);
+            view.setScaleY(scale);
+        }
+    }
+
+    private void updateAdapterScaleAndAlpha(final float alpha, final float scale) {
+        final List<View> pageViews = mAdapter.getViews();
+        final int curPos = mViewPager.getCurrentItem();
+
+        if(pageViews.size() > 0) {
+            final View currentPage = pageViews.get(curPos);
+            updateScaleAndAlpha(((ViewGroup)currentPage).getChildAt(0), 1.0F, mCurrentItemScale);
+
+            if(pageViews.size() < 2) {
+                return;
+            }
+            //make sure View's width & height are measured.
+            currentPage.postDelayed(WXThread.secure(new Runnable() {
+                @Override
+                public void run() {
+                    //change left and right page's translation
+                    updateNeighbor(currentPage, alpha, scale);
+
+                }
+            }), 17);
+
+            // make sure only display view current, left, right.
+            int left = (curPos == 0) ? pageViews.size()-1 : curPos-1;
+            int right = (curPos == pageViews.size()-1) ? 0 : curPos+1;
+            for(int i =0; i<mAdapter.getRealCount(); i++) {
+                if(i != left && i != curPos && i != right) {
+                    ((ViewGroup)pageViews.get(i)).getChildAt(0).setAlpha(0F);
+                }
+            }
+        }
+    }
+
+    private void updateNeighbor(View currentPage, final float alpha, final float scale) {
+        final List<View> pageViews = mAdapter.getViews();
+        final int curPos = mViewPager.getCurrentItem();
+
+        float translation = calculateTranslation(currentPage);
+        int left = (curPos == 0) ? pageViews.size()-1 : curPos-1;
+        View leftPage = pageViews.get(left);
+        int right = (curPos == pageViews.size()-1) ? 0 : curPos+1;
+        View rightPage = pageViews.get(right);
+
+        if(pageViews.size() == 2) {
+            if(curPos == 0) {
+                moveRight(rightPage, translation, alpha, scale);
+            }else if(curPos == 1) {
+                moveLeft(leftPage, translation, alpha, scale);
+            }
+        } else {
+            moveLeft(leftPage, translation, alpha, scale);
+            moveRight(rightPage, translation, alpha, scale);
+        }
+    }
+
+    private void moveLeft(View page, float translation, float alpha, float scale) {
+        updateScaleAndAlpha(((ViewGroup)page).getChildAt(0), alpha, scale);
+        page.setTranslationX(translation);
+        ((ViewGroup)page).getChildAt(0).setTranslationX(translation);
+    }
+    private void moveRight(View page, float translation, float alpha, float scale) {
+        moveLeft(page, -translation, alpha, scale);
+    }
+
+    @WXComponentProp(name = NEIGHBOR_SCALE)
+    public void setNeighborScale(String input) {
+        float neighborScale = DEFAULT_NEIGHBOR_SCALE;
+        if (!TextUtils.isEmpty(input)) {
+            try {
+                neighborScale = Float.parseFloat(input);
+            } catch (NumberFormatException e) {
+            }
+        }
+
+        // addSubView is called before setProperty, so we need to modify the neighbor view in mAdapter.
+        if(this.mNeighborScale != neighborScale) {
+            this.mNeighborScale = neighborScale;
+            updateAdapterScaleAndAlpha(-1, neighborScale);
+        }
+    }
+
+    @WXComponentProp(name = NEIGHBOR_ALPHA)
+    public void setNeighborAlpha(String input) {
+        float neighborAlpha = DEFAULT_NEIGHBOR_ALPHA;
+        if (!TextUtils.isEmpty(input)) {
+            try {
+                neighborAlpha = Float.parseFloat(input);
+            } catch (NumberFormatException e) {
+            }
+        }
+
+        // The same work as setNeighborScale()
+        if(this.mNeighborAlpha != neighborAlpha) {
+            this.mNeighborAlpha = neighborAlpha;
+            updateAdapterScaleAndAlpha(neighborAlpha, -1);
+        }
+    }
+
+    @WXComponentProp(name = NEIGHBOR_SPACE)
+    @SuppressWarnings("unused")
+    public void setNeighborSpace(String input) {
+        float neighborSpace = DEFAULT_NEIGHBOR_SPACE;
+        if (!TextUtils.isEmpty(input)) {
+            try {
+                neighborSpace = Float.parseFloat(input);
+            } catch (NumberFormatException e) {
+            }
+        }
+
+        if(this.mNeighborSpace != neighborSpace) {
+            this.mNeighborSpace = neighborSpace;
+        }
+    }
+
+    @WXComponentProp(name = CURRENT_ITEM_SCALE)
+    @SuppressWarnings("unused")
+    public void setCurrentItemScale(String input) {
+        float currentItemScale = DEFAULT_CURRENT_ITEM_SCALE;
+        if (!TextUtils.isEmpty(input)) {
+            try {
+                currentItemScale = Float.parseFloat(input);
+            } catch (NumberFormatException e) {
+            }
+        }
+
+        if(this.mCurrentItemScale != currentItemScale) {
+            this.mCurrentItemScale = currentItemScale;
+            updateAdapterScaleAndAlpha(-1, -1);
+        }
+    }
+
+    @Override
+    protected boolean setProperty(String key, Object param) {
+        String input;
+        switch (key) {
+            case NEIGHBOR_SCALE:
+                input = WXUtils.getString(param, null);
+                if (input != null) {
+                    setNeighborScale(input);
+                }
+                return true;
+            case NEIGHBOR_ALPHA:
+                input = WXUtils.getString(param, null);
+                if (input != null) {
+                    setNeighborAlpha(input);
+                }
+                return true;
+            case NEIGHBOR_SPACE:
+                input = WXUtils.getString(param, null);
+                if (input != null) {
+                    setNeighborSpace(input);
+                }
+                return true;
+            case CURRENT_ITEM_SCALE:
+                input = WXUtils.getString(param, null);
+                if (input != null) {
+                    setCurrentItemScale(input);
+                }
+                return true;
+        }
+        return super.setProperty(key, param);
+    }
+
+    /**
+     * we need add translation for left and right card view.
+     * */
+    private float calculateTranslation(@NonNull View hostPage) {
+        if(!(hostPage instanceof ViewGroup)) {
+            return 0;
+        }
+        View realView = ((ViewGroup)hostPage).getChildAt(0);
+        float translation = (hostPage.getMeasuredWidth()-realView.getMeasuredWidth()*mNeighborScale)/4;
+        translation += ((hostPage.getMeasuredWidth()-realView.getMeasuredWidth() * mCurrentItemScale)/2 - WXViewUtils.getRealPxByWidth(mNeighborSpace, getInstance().getInstanceViewPortWidth()))/2 ;
+        return translation;
+    }
+
+    // Here is the trick.
+     class ZoomTransformer implements ViewPager.PageTransformer {
+        @Override
+        public void transformPage(View page, float position) {
+            int pagePosition = mAdapter.getPagePosition(page);
+            int curPosition = mViewPager.getCurrentItem();
+
+            int realCount = mAdapter.getRealCount();
+
+            boolean ignore = false;
+            if(curPosition != 0 && curPosition != realCount - 1 && Math.abs(pagePosition - curPosition) > 1)  {
+                ignore = true;
+            }
+            if(curPosition == 0 && pagePosition < realCount - 1 && pagePosition > 1) {
+                ignore = true;
+            }
+            if(curPosition == realCount - 1 && pagePosition < realCount - 2 && pagePosition > 0) {
+                ignore = true;
+            }
+            // just transfer the neighbor(left & right) page.
+            if(ignore) {
+                return;
+            }
+
+            View realView = ((ViewGroup)page).getChildAt(0);
+            if(realView == null){
+                return;
+            }
+            float alpha, scale;
+
+            if(position <= (-realCount + 1)) {
+                position = position + realCount;
+            }
+            if(position >= realCount - 1) {
+                position = position - realCount;
+            }
+
+            if (position >= -1 && position <= 1) {
+                float factor = Math.abs(Math.abs(position) - 1);
+                scale = mNeighborScale + factor * (mCurrentItemScale - mNeighborScale);
+                alpha = (1- mNeighborAlpha) * factor + mNeighborAlpha;
+
+                float translation = calculateTranslation(page);
+                if(position > 0){
+                    translation = (position*translation);
+                    realView.setTranslationX(-translation);
+                    page.setTranslationX(-translation);
+                }else if(position == 0){
+                    page.setTranslationX(0);
+                    realView.setTranslationX(0);
+                    updateAdapterScaleAndAlpha(mNeighborAlpha, mNeighborScale);
+                }else{
+                    if(realCount == 2 && Math.abs(position) == 1) {
+                        return;
+                    }
+                    translation = (-position*translation);
+                    realView.setTranslationX(translation);
+                    page.setTranslationX(translation);
+                }
+                realView.setScaleX(scale);
+                realView.setScaleY(scale);
+                realView.setAlpha(alpha);
+            }
+
+        }
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXSwitch.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXSwitch.java
new file mode 100644
index 0000000..32c06a2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXSwitch.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.widget.CompoundButton;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.layout.ContentBoxMeasurement;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXSwitchView;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component(lazyload = false)
+
+public class WXSwitch extends WXComponent<WXSwitchView> {
+
+  private CompoundButton.OnCheckedChangeListener mListener;
+
+  @Deprecated
+  public WXSwitch(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  public WXSwitch(final WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+    super(instance, parent, isLazy, basicComponentData);
+    setContentBoxMeasurement(new ContentBoxMeasurement() {
+      /** uiThread = false **/
+      @Override
+      public void measureInternal(float width, float height, int widthMeasureMode, int heightMeasureMode) {
+        mMeasureWidth = 0;
+        mMeasureHeight = 0;
+        try {
+          WXSwitchView wxSwitchView = new WXSwitchView(instance.getContext());
+          int widthSpec, heightSpec;
+          heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+          if (Float.isNaN(width)) {
+            widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+          } else {
+            widthSpec = View.MeasureSpec.makeMeasureSpec((int) width, View.MeasureSpec.AT_MOST);
+          }
+
+          wxSwitchView.measure(widthSpec, heightSpec);
+          mMeasureWidth = wxSwitchView.getMeasuredWidth();
+          mMeasureHeight = wxSwitchView.getMeasuredHeight();
+        } catch (RuntimeException e) {
+          WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+      }
+
+      /** uiThread = false **/
+      @Override
+      public void layoutBefore() {
+      }
+
+      /** uiThread = false **/
+      @Override
+      public void layoutAfter(float computedWidth, float computedHeight) {
+      }
+    });
+  }
+
+  @Override
+  protected WXSwitchView initComponentHostView(@NonNull Context context) {
+    return new WXSwitchView(context);
+  }
+
+
+  @Override
+  public void addEvent(String type) {
+    super.addEvent(type);
+    if (type != null && type.equals(Constants.Event.CHANGE) && getHostView() != null) {
+      if (mListener == null) {
+        mListener = new CompoundButton.OnCheckedChangeListener() {
+          @Override
+          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            Map<String, Object> params = new HashMap<>(2);
+            params.put("value", isChecked);
+
+            Map<String, Object> domChanges = new HashMap<>();
+            Map<String, Object> attrsChanges = new HashMap<>();
+            attrsChanges.put("checked",Boolean.toString(isChecked));
+            domChanges.put("attrs",attrsChanges);
+            fireEvent(Constants.Event.CHANGE, params,domChanges);
+          }
+        };
+      }
+      getHostView().setOnCheckedChangeListener(mListener);
+    }
+  }
+
+  @Override
+  protected void removeEventFromView(String type) {
+    super.removeEventFromView(type);
+    if (getHostView() != null && Constants.Event.CHANGE.equals(type)) {
+      getHostView().setOnCheckedChangeListener(null);
+    }
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.CHECKED:
+        Boolean result = WXUtils.getBoolean(param, null);
+        if (result != null) {
+          setChecked(result);
+        }
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @WXComponentProp(name = Constants.Name.CHECKED)
+  public void setChecked(boolean checked) {
+    getHostView().setOnCheckedChangeListener(null);
+    getHostView().setChecked(checked);
+    getHostView().setOnCheckedChangeListener(mListener);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXText.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXText.java
new file mode 100644
index 0000000..729414b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXText.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.annotation.NonNull;
+import android.support.v4.content.LocalBroadcastManager;
+import android.text.Layout;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.layout.measurefunc.TextContentBoxMeasurement;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.flat.FlatComponent;
+import org.apache.weex.ui.flat.widget.TextWidget;
+import org.apache.weex.ui.view.WXTextView;
+import org.apache.weex.utils.FontDO;
+import org.apache.weex.utils.TypefaceUtil;
+import org.apache.weex.utils.WXLogUtils;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Text component
+ */
+@Component(lazyload = false)
+public class WXText extends WXComponent<WXTextView> implements FlatComponent<TextWidget> {
+
+  private TextWidget mTextWidget;
+
+  /**
+   * The default text size
+   **/
+  public static final int sDEFAULT_SIZE = 32;
+  private BroadcastReceiver mTypefaceObserver;
+  private String mFontFamily;
+
+  @Override
+  public boolean promoteToView(boolean checkAncestor) {
+    if (null != getInstance().getFlatUIContext()) {
+      return getInstance().getFlatUIContext().promoteToView(this, checkAncestor, WXText.class);
+    }
+    return false;
+  }
+
+  @Override
+  @NonNull
+  public TextWidget getOrCreateFlatWidget() {
+    if (mTextWidget == null) {
+      mTextWidget = new TextWidget(getInstance().getFlatUIContext());
+    }
+    return mTextWidget;
+  }
+
+  @Override
+  public boolean isVirtualComponent() {
+    return !promoteToView(true);
+  }
+
+  public static class Creator implements ComponentCreator {
+    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      return new WXText(instance, parent, basicComponentData);
+    }
+  }
+
+  @Deprecated
+  public WXText(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, basicComponentData);
+  }
+
+  public WXText(WXSDKInstance instance,
+                WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+    setContentBoxMeasurement(new TextContentBoxMeasurement(this));
+  }
+
+  @Override
+  protected WXTextView initComponentHostView(@NonNull Context context) {
+    WXTextView textView = new WXTextView(context);
+    textView.holdComponent(this);
+    return textView;
+  }
+
+  @Override
+  public void updateExtra(Object extra) {
+    super.updateExtra(extra);
+    if(extra instanceof Layout) {
+      final Layout layout = (Layout) extra;
+      if (!promoteToView(true)) {
+        getOrCreateFlatWidget().updateTextDrawable(layout);
+      } else if (getHostView() != null && !extra.equals(getHostView().getTextLayout())) {
+        getHostView().setTextLayout(layout);
+        getHostView().invalidate();
+      }
+    }
+  }
+
+  @Override
+  protected void setAriaLabel(String label) {
+    WXTextView text = getHostView();
+    if (text != null) {
+      text.setAriaLabel(label);
+    }
+  }
+
+  @Override
+  public void refreshData(WXComponent component) {
+    super.refreshData(component);
+    if (component instanceof WXText) {
+      updateExtra(component.getExtra());
+    }
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.LINES:
+      case Constants.Name.FONT_SIZE:
+      case Constants.Name.FONT_WEIGHT:
+      case Constants.Name.FONT_STYLE:
+      case Constants.Name.COLOR:
+      case Constants.Name.TEXT_DECORATION:
+      case Constants.Name.TEXT_ALIGN:
+      case Constants.Name.TEXT_OVERFLOW:
+      case Constants.Name.LINE_HEIGHT:
+      case Constants.Name.VALUE:
+        return true;
+      case Constants.Name.FONT_FAMILY:
+        if (param != null) {
+          registerTypefaceObserver(param.toString());
+        }
+        return true;
+      default:
+        return super.setProperty(key, param);
+    }
+  }
+
+  @Override
+  protected Object convertEmptyProperty(String propName, Object originalValue) {
+    switch (propName) {
+      case Constants.Name.FONT_SIZE:
+        return WXText.sDEFAULT_SIZE;
+      case Constants.Name.COLOR:
+        return "black";
+    }
+    return super.convertEmptyProperty(propName, originalValue);
+  }
+
+  @Override
+  protected void createViewImpl() {
+    if(promoteToView(true)) {
+      super.createViewImpl();
+    }
+  }
+
+  @Override
+  public void destroy() {
+    super.destroy();
+    if (WXEnvironment.getApplication() != null && mTypefaceObserver != null) {
+      WXLogUtils.d("WXText", "Unregister the typeface observer");
+      LocalBroadcastManager.getInstance(WXEnvironment.getApplication()).unregisterReceiver(mTypefaceObserver);
+      mTypefaceObserver = null;
+    }
+  }
+
+  private void registerTypefaceObserver(String desiredFontFamily) {
+    if (WXEnvironment.getApplication() == null) {
+      WXLogUtils.w("WXText", "ApplicationContent is null on register typeface observer");
+      return;
+    }
+    mFontFamily = desiredFontFamily;
+    if (mTypefaceObserver != null) {
+      return;
+    }
+
+    mTypefaceObserver = new BroadcastReceiver() {
+      @Override
+      public void onReceive(Context context, Intent intent) {
+        String fontFamily = intent.getStringExtra("fontFamily");
+        if (!mFontFamily.equals(fontFamily)) {
+          return;
+        }
+
+        FontDO fontDO = TypefaceUtil.getFontDO(fontFamily);
+        if (fontDO != null && fontDO.getTypeface() != null && getHostView() != null) {
+          WXTextView hostView = getHostView();
+          Layout layout = hostView.getTextLayout();
+          if (layout != null) {
+            layout.getPaint().setTypeface(fontDO.getTypeface());
+          } else {
+            WXLogUtils.d("WXText", "Layout not created");
+          }
+          WXBridgeManager
+              .getInstance().markDirty(getInstanceId(), getRef(), true);
+          forceRelayout();
+
+        }
+      }
+    };
+
+    LocalBroadcastManager.getInstance(WXEnvironment.getApplication()).registerReceiver(mTypefaceObserver, new IntentFilter(TypefaceUtil.ACTION_TYPE_FACE_AVAILABLE));
+  }
+
+
+  @Override
+  protected void layoutDirectionDidChanged(boolean isRTL) {
+    forceRelayout();
+  }
+
+  private void forceRelayout(){
+    WXBridgeManager.getInstance().post(new Runnable() {
+      @Override
+      public void run() {
+        if(contentBoxMeasurement instanceof TextContentBoxMeasurement){
+          ((TextContentBoxMeasurement) contentBoxMeasurement).forceRelayout();
+        }
+      }
+    });
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXTextDecoration.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXTextDecoration.java
new file mode 100644
index 0000000..5f6db1b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXTextDecoration.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+public enum WXTextDecoration {
+  INVALID,
+  NONE,
+  UNDERLINE,
+  LINETHROUGH,
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXVContainer.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXVContainer.java
new file mode 100644
index 0000000..6b238e4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXVContainer.java
@@ -0,0 +1,629 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat;
+import android.util.Pair;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXImageView;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.ArrayList;
+
+/**
+ * All container components must implement this class
+ */
+public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
+
+  private static final String TAG = "WXVContainer";
+  protected ArrayList<WXComponent> mChildren = new ArrayList<>();
+  private BoxShadowHost mBoxShadowHost;
+
+  @Deprecated
+  public WXVContainer(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  @Deprecated
+  public WXVContainer(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  public WXVContainer(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  /**
+   * Container will get focus before any of its descendants.
+   */
+  public void interceptFocus() {
+    T host = getHostView();
+    if (host != null) {
+      host.setFocusable(true);
+      host.setFocusableInTouchMode(true);
+      host.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+      host.requestFocus();
+    }
+  }
+
+  /**
+   * Container will can not receive focus
+   */
+  public void ignoreFocus() {
+    T host = getHostView();
+    if (host != null) {
+      host.setFocusable(false);
+      host.setFocusableInTouchMode(false);
+      host.clearFocus();
+    }
+  }
+
+  /**
+   * Offset top for children layout.
+   */
+  protected int getChildrenLayoutTopOffset() {
+    return 0;
+  }
+
+  /**
+   * use {@link #getHostView()} instead
+   */
+  @Deprecated
+  public ViewGroup getView() {
+    return getHostView();
+  }
+
+  @Override
+  public void applyLayoutAndEvent(WXComponent component) {
+    if (!isLazy()) {
+      if (component == null) {
+        component = this;
+      }
+      super.applyLayoutAndEvent(component);
+      int count = childCount();
+      for (int i = 0; i < count; i++) {
+        WXComponent child = getChild(i);
+        child.applyLayoutAndEvent(((WXVContainer) component).getChild(i));
+      }
+    }
+  }
+
+  /**
+   * Get or generate new layout parameter for child view
+   */
+  public ViewGroup.LayoutParams getChildLayoutParams(WXComponent child, View childView, int width, int height, int left, int right, int top, int bottom) {
+    ViewGroup.LayoutParams lp = null;
+    if (childView != null) {
+      lp = childView.getLayoutParams();
+    }
+
+    if(lp == null) {
+      lp = new ViewGroup.LayoutParams(width,height);
+    }else{
+      lp.width = width;
+      lp.height = height;
+      if(lp instanceof ViewGroup.MarginLayoutParams){
+        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, left, top, right, bottom);
+      }
+    }
+    return lp;
+  }
+
+
+  public Scrollable getFirstScroller() {
+    if (this instanceof Scrollable) {
+      return (Scrollable) this;
+    } else {
+      for (int i = 0; i < getChildCount(); i++) {
+        Scrollable scrollable = getChild(i).getFirstScroller();
+        if (scrollable != null) {
+          return scrollable;
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public void bindData(WXComponent component) {
+    if (!isLazy()) {
+      if (component == null) {
+        component = this;
+      }
+      super.bindData(component);
+      int count = childCount();
+      for (int i = 0; i < count; i++) {
+        getChild(i).bindData(((WXVContainer) component).getChild(i));
+      }
+    }
+  }
+
+  @Override
+  public void refreshData(WXComponent component) {
+    if (component == null) {
+      component = this;
+    }
+    super.refreshData(component);
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).refreshData(((WXVContainer) component).getChild(i));
+    }
+  }
+
+  /**
+   * return real View
+   */
+  @Override
+  public ViewGroup getRealView() {
+    return (ViewGroup) super.getRealView();
+  }
+
+  @Override
+  public void createViewImpl() {
+    super.createViewImpl();
+    int count = childCount();
+    for (int i = 0; i < count; ++i) {
+      createChildViewAt(i);
+    }
+    if (getHostView() != null) {
+      getHostView().setClipToPadding(false);
+    }
+  }
+
+  @Override
+  public void destroy() {
+    if (mChildren != null) {
+      int count = mChildren.size();
+      for (int i = 0; i < count; ++i) {
+        mChildren.get(i).destroy();
+      }
+      mChildren.clear();
+    }
+    super.destroy();
+  }
+
+  /**
+   * recycle component resources
+   */
+  public void recycled() {
+    if (mChildren != null && !isFixed() && getAttrs().canRecycled()) {
+      int count = mChildren.size();
+      for (int i = 0; i < count; ++i) {
+        mChildren.get(i).recycled();
+      }
+    }
+    super.recycled();
+
+  }
+
+  @Override
+  public View detachViewAndClearPreInfo() {
+    View original = super.detachViewAndClearPreInfo();
+    if (mChildren != null) {
+      int count = childCount();
+      for (int i = 0; i < count; ++i) {
+        mChildren.get(i).detachViewAndClearPreInfo();
+      }
+    }
+    return original;
+  }
+
+  public int childCount() {
+    return mChildren == null ? 0 : mChildren.size();
+  }
+
+  public WXComponent getChild(int index) {
+    if (mChildren == null || index < 0 || index >= mChildren.size()) {
+      //To avoid index out of bounds
+      return null;
+    }
+    return mChildren.get(index);
+  }
+
+  public int getChildCount() {
+    return childCount();
+  }
+
+  public void addChild(WXComponent child) {
+    addChild(child, -1);
+  }
+
+  public void addChild(WXComponent child, int index) {
+    if (child == null || index < -1) {
+      return;
+    }
+    child.mDeepInComponentTree = this.mDeepInComponentTree +1;
+    getInstance().setMaxDomDeep(child.mDeepInComponentTree);
+    int count = mChildren.size();
+    index = index >= count ? -1 : index;
+    if (index == -1) {
+      mChildren.add(child);
+    } else {
+      mChildren.add(index, child);
+    }
+  }
+
+  public final int indexOf(WXComponent comp) {
+    return mChildren.indexOf(comp);
+  }
+
+  public void createChildViewAt(int index) {
+    Pair<WXComponent, Integer> ret = rearrangeIndexAndGetChild(index);
+    if (ret.first != null) {
+      WXComponent child = ret.first;
+      child.createView();
+      if (!child.isVirtualComponent()) {
+        addSubView(child.getHostView(), ret.second);
+      }
+    }
+  }
+
+  protected Pair<WXComponent, Integer> rearrangeIndexAndGetChild(int index) {
+    int indexToCreate = index;
+    if (indexToCreate < 0) {
+      indexToCreate = childCount() - 1;
+    }
+
+    if (indexToCreate < 0) {
+      return new Pair<>(null, indexToCreate);
+    } else {
+      return new Pair<>(getChild(indexToCreate), indexToCreate);
+    }
+  }
+
+  public void addSubView(View child, int index) {
+    if (child == null || getRealView() == null) {
+      return;
+    }
+
+    int count = getRealView().getChildCount();
+    index = index >= count ? -1 : index;
+    if (index == -1) {
+      getRealView().addView(child);
+    } else {
+      getRealView().addView(child, index);
+    }
+    WXSDKInstance instance = getInstance();
+    if (null != instance){
+      instance.getApmForInstance().hasAddView = true;
+    }
+  }
+
+  public void remove(WXComponent child, boolean destroy) {
+    if (child == null || mChildren == null || mChildren.size() == 0) {
+      return;
+    }
+
+    mChildren.remove(child);
+    if (getInstance() != null
+            && getInstance().getRootView() != null
+            && child.isFixed()) {
+      getInstance().removeFixedView(child.getHostView());
+    } else if (getRealView() != null) {
+      if (!child.isVirtualComponent()) {
+        ViewParent parent = null;
+        if(child.getParent() instanceof  WXScroller){
+          if(child.getHostView() != null){
+            parent = child.getHostView().getParent();
+          }
+        }
+        if(parent != null && parent instanceof  ViewGroup){
+          ((ViewGroup) parent).removeView(child.getHostView());
+        }else{
+          getRealView().removeView(child.getHostView());
+        }
+      } else {
+        child.removeVirtualComponent();
+      }
+    }
+    if (destroy) {
+      child.destroy();
+    }
+  }
+
+  @Override
+  public void notifyAppearStateChange(String wxEventType, String direction) {
+    super.notifyAppearStateChange(wxEventType, direction);
+    if (getHostView() == null || mChildren == null) {
+      return;
+    }
+    for (WXComponent component : mChildren) {
+      if (component.getHostView() != null && !(component.getHostView().getVisibility() == View.VISIBLE)) {
+        wxEventType = Constants.Event.DISAPPEAR;
+      }
+      component.notifyAppearStateChange(wxEventType, direction);
+    }
+  }
+
+  /********************************************************
+   *  begin hook Activity life cycle callback             *
+   ********************************************************/
+  @Override
+  public void onActivityCreate() {
+    super.onActivityCreate();
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityCreate();
+    }
+  }
+
+  @Override
+  public void onActivityStart() {
+    super.onActivityStart();
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityStart();
+    }
+
+  }
+
+  @Override
+  public void onActivityPause() {
+    super.onActivityPause();
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityPause();
+    }
+  }
+
+  @Override
+  public void onActivityResume() {
+    super.onActivityResume();
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityResume();
+    }
+  }
+
+  @Override
+  public void onActivityStop() {
+    super.onActivityStop();
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityStop();
+    }
+  }
+
+  @Override
+  public void onActivityDestroy() {
+    super.onActivityDestroy();
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityDestroy();
+    }
+
+  }
+
+  @Override
+  public boolean onActivityBack() {
+    super.onActivityBack();
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityBack();
+    }
+    return false;
+  }
+
+  @Override
+  public void onActivityResult(int requestCode, int resultCode, Intent data) {
+    super.onActivityResult(requestCode, resultCode, data);
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onActivityResult(requestCode, resultCode, data);
+    }
+
+  }
+
+  public boolean onCreateOptionsMenu(Menu menu) {
+    super.onCreateOptionsMenu(menu);
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onCreateOptionsMenu(menu);
+    }
+    return false;
+  }
+
+
+  @Override
+  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+
+    int count = childCount();
+    for (int i = 0; i < count; i++) {
+      getChild(i).onRequestPermissionsResult(requestCode, permissions, grantResults);
+    }
+  }
+
+  @Override
+  public void onRenderFinish(@RenderState int state) {
+    for (int i = 0; i < getChildCount(); i++) {
+      WXComponent child = getChild(i);
+      child.mTraceInfo.uiQueueTime = mTraceInfo.uiQueueTime;
+      child.onRenderFinish(state);
+    }
+    super.onRenderFinish(state);
+  }
+
+  @JSMethod
+  public void releaseImageList(String viewTreeRecycle){
+    if(getHostView() == null
+            || !ViewCompat.isAttachedToWindow(getHostView())
+            || !(getHostView() instanceof  ViewGroup)){
+      return;
+    }
+    boolean isViewTree = WXUtils.getBoolean(viewTreeRecycle, false);
+    if(isViewTree){
+      doViewTreeRecycleImageView(getHostView(), true);
+    }else{
+      int count = getChildCount();
+      for(int i=0; i<count; i++){
+        WXComponent component =  getChild(i);
+        if(component instanceof  WXImage && ((WXImage) component).getHostView() instanceof WXImageView){
+          WXImageView imageView = (WXImageView) component.getHostView();
+          if(imageView != null && ViewCompat.isAttachedToWindow(imageView)){
+            imageView.autoReleaseImage();
+          }
+        }else if(component instanceof  WXVContainer){
+          ((WXVContainer) component).releaseImageList(viewTreeRecycle);
+        }
+      }
+    }
+  }
+
+  @JSMethod
+  public void recoverImageList(String viewTreeRecycle){
+    if(getHostView() == null
+            || !ViewCompat.isAttachedToWindow(getHostView())
+            || !(getHostView() instanceof  ViewGroup)){
+      return;
+    }
+    boolean isViewTree = WXUtils.getBoolean(viewTreeRecycle, false);
+    if(isViewTree){
+      doViewTreeRecycleImageView(getHostView(), false);
+    }else{
+      int count = getChildCount();
+      for(int i=0; i<count; i++){
+        WXComponent component =  getChild(i);
+        if(component instanceof  WXImage && ((WXImage) component).getHostView() instanceof WXImageView){
+          WXImageView imageView = (WXImageView) component.getHostView();
+          if(imageView != null && ViewCompat.isAttachedToWindow(imageView)){
+            imageView.autoRecoverImage();
+          }
+        }else if(component instanceof  WXVContainer){
+          ((WXVContainer) component).recoverImageList(viewTreeRecycle);
+        }
+      }
+    }
+  }
+
+  /**
+   * transverse view tree, and recycle wximageview in container
+   * */
+  private void doViewTreeRecycleImageView(ViewGroup viewGroup, boolean isRelease){
+    int count = viewGroup.getChildCount();
+    for(int i=0; i<count; i++){
+      View view = viewGroup.getChildAt(i);
+      if(view instanceof  WXImageView){
+        if(isRelease){
+          ((WXImageView) view).autoReleaseImage();
+        }else{
+          ((WXImageView) view).autoRecoverImage();
+        }
+      }else if(view instanceof  ViewGroup){
+        doViewTreeRecycleImageView((ViewGroup) view, isRelease);
+      }
+    }
+  }
+
+
+  public void requestDisallowInterceptTouchEvent(boolean requestDisallowInterceptTouchEvent) {
+    if(mGesture != null){
+      if(mGesture.isRequestDisallowInterceptTouchEvent()){
+        return;
+      }
+      mGesture.setRequestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
+    }
+    if(getParent() != null){
+      getParent().requestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
+    }
+  }
+
+  /********************************
+   *  end hook Activity life cycle callback
+   ********************************************************/
+
+  public @Nullable
+  View getBoxShadowHost(boolean isClear) {
+    if (isClear) {
+      // Return existed host if want clear shadow
+      return mBoxShadowHost;
+    }
+
+    ViewGroup hostView = getHostView();
+    if (hostView == null) {
+      return null;
+    }
+
+    try {
+      String type = getComponentType();
+      if (WXBasicComponentType.DIV.equals(type)) {
+        WXLogUtils.d("BoxShadow", "Draw box-shadow with BoxShadowHost on div: " + toString());
+        if (mBoxShadowHost == null) {
+          mBoxShadowHost = new BoxShadowHost(getContext());
+          WXViewUtils.setBackGround(mBoxShadowHost, null, this);
+
+          hostView.addView(mBoxShadowHost);
+        }
+
+        CSSShorthand padding = this.getPadding();
+        CSSShorthand border = this.getBorder();
+
+        int left = (int) (padding.get(CSSShorthand.EDGE.LEFT) + border.get(CSSShorthand.EDGE.LEFT));
+        int top = (int) (padding.get(CSSShorthand.EDGE.TOP) + border.get(CSSShorthand.EDGE.TOP));
+        int right = (int) (padding.get(CSSShorthand.EDGE.RIGHT) + border.get(CSSShorthand.EDGE.RIGHT));
+        int bottom = (int) (padding.get(CSSShorthand.EDGE.BOTTOM) + border.get(CSSShorthand.EDGE.BOTTOM));
+
+        ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(hostView.getLayoutParams()) ;
+        this.setMarginsSupportRTL(layoutParams, -left, -top, -right, -bottom);
+
+        mBoxShadowHost.setLayoutParams(layoutParams);
+        
+        hostView.removeView(mBoxShadowHost);
+        hostView.addView(mBoxShadowHost);
+        return mBoxShadowHost;
+      }
+    } catch (Throwable t) {
+      WXLogUtils.w("BoxShadow", t);
+    }
+    return hostView;
+  }
+
+  private class BoxShadowHost extends View {
+    public BoxShadowHost(Context context) {
+      super(context);
+    }
+  }
+
+  public void appendTreeCreateFinish() {
+    
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXVideo.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXVideo.java
new file mode 100644
index 0000000..a4f875f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXVideo.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.WXVideoView;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.weex.ui.view.WXVideoView.Wrapper;
+
+@Component(lazyload = false)
+
+public class WXVideo extends WXComponent<FrameLayout> {
+
+  private boolean mAutoPlay;
+  private Wrapper mWrapper;
+
+  /**
+   * package
+   **/
+  boolean mPrepared;
+  private boolean mError;
+
+  @Deprecated
+  public WXVideo(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+  public WXVideo(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+    super(instance, parent, isLazy, basicComponentData);
+  }
+
+  @Override
+  protected FrameLayout initComponentHostView(@NonNull Context context) {
+    final Wrapper video = new Wrapper(context);
+    video.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+
+      @Override
+      public boolean onError(MediaPlayer mp, int what, int extra) {
+        if (WXEnvironment.isApkDebugable()) {
+          WXLogUtils.d("Video", "onError:" + what);
+        }
+        video.getProgressBar().setVisibility(View.GONE);
+        mPrepared = false;
+        mError = true;
+
+        if (getEvents().contains(Constants.Event.FAIL)) {
+          WXVideo.this.notify(Constants.Event.FAIL, Constants.Value.STOP);
+        }
+        return true;
+      }
+    });
+
+    video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+
+      @Override
+      public void onPrepared(MediaPlayer mediaPlayer) {
+        if (WXEnvironment.isApkDebugable()) {
+          WXLogUtils.d("Video", "onPrepared");
+        }
+        video.getProgressBar().setVisibility(View.GONE);
+        mPrepared = true;
+        if (mAutoPlay) {
+          video.start();
+        }
+
+        //callback from video view, so videoview should not null
+        WXVideoView videoView = video.getVideoView();
+        videoView.seekTo(5);
+
+        if (video.getMediaController() != null) {
+          if (!mStopped) {
+            video.getMediaController().show(3);
+          } else {
+            video.getMediaController().hide();
+          }
+        }
+
+        mStopped = false;
+      }
+    });
+
+    video.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+
+      @Override
+      public void onCompletion(MediaPlayer mediaPlayer) {
+        if (WXEnvironment.isApkDebugable()) {
+          WXLogUtils.d("Video", "onCompletion");
+        }
+        if (getEvents().contains(Constants.Event.FINISH)) {
+          WXVideo.this.notify(Constants.Event.FINISH, Constants.Value.STOP);
+        }
+      }
+    });
+
+    video.setOnVideoPauseListener(new WXVideoView.VideoPlayListener() {
+
+      @Override
+      public void onPause() {
+        if (WXEnvironment.isApkDebugable()) {
+          WXLogUtils.d("Video", "onPause");
+        }
+        if (getEvents().contains(Constants.Event.PAUSE)) {
+          WXVideo.this.notify(Constants.Event.PAUSE, Constants.Value.PAUSE);
+        }
+      }
+
+      @Override
+      public void onStart() {
+        if (WXEnvironment.isApkDebugable()) {
+          WXLogUtils.d("Video", "onStart");
+        }
+
+        if (getEvents().contains(Constants.Event.START)) {
+          WXVideo.this.notify(Constants.Event.START, Constants.Value.PLAY);
+        }
+      }
+    });
+    mWrapper = video;
+    return video;
+  }
+
+  private void notify(String event, String newStatus) {
+    Map<String, Object> params = new HashMap<>(2);
+    params.put(Constants.Name.PLAY_STATUS, newStatus);
+    params.put("timeStamp", System.currentTimeMillis());
+
+    Map<String, Object> domChanges = new HashMap<>();
+    Map<String, Object> attrsChanges = new HashMap<>();
+    attrsChanges.put(Constants.Name.PLAY_STATUS, newStatus);
+    domChanges.put("attrs", attrsChanges);
+
+    WXSDKManager.getInstance().fireEvent(getInstanceId(), getRef(), event, params, domChanges);
+  }
+
+  @Override
+  public void bindData(WXComponent component) {
+    super.bindData(component);
+    addEvent(Constants.Event.APPEAR);
+  }
+
+  @Override
+  public void notifyAppearStateChange(String wxEventType, String direction) {
+    super.notifyAppearStateChange(wxEventType, direction);
+    mWrapper.createVideoViewIfVisible();
+  }
+
+  @Override
+  public void destroy() {
+    super.destroy();
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case Constants.Name.SRC:
+        String src = WXUtils.getString(param, null);
+        if (src != null) {
+          setSrc(src);
+        }
+        return true;
+      case Constants.Name.AUTO_PLAY:
+      case Constants.Name.AUTOPLAY:
+        Boolean result = WXUtils.getBoolean(param, null);
+        if (result != null) {
+          setAutoPlay(result);
+        }
+        return true;
+      case Constants.Name.ZORDERTOP:
+        Boolean zOrderTop = WXUtils.getBoolean(param, null);
+        if (zOrderTop != null) {
+            mWrapper.getVideoView().setZOrderOnTop(zOrderTop);
+        }
+        return true;
+      case Constants.Name.PLAY_STATUS:
+        String status = WXUtils.getString(param, null);
+        if (status != null) {
+          setPlaystatus(status);
+        }
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @WXComponentProp(name = Constants.Name.SRC)
+  public void setSrc(String src) {
+    if (TextUtils.isEmpty(src) || getHostView() == null) {
+      return;
+    }
+
+    if (!TextUtils.isEmpty(src)) {
+      WXSDKInstance instance = getInstance();
+      mWrapper.setVideoURI(instance.rewriteUri(Uri.parse(src), URIAdapter.VIDEO));
+      mWrapper.getProgressBar().setVisibility(View.VISIBLE);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.AUTO_PLAY)
+  public void setAutoPlay(boolean autoPlay) {
+    mAutoPlay = autoPlay;
+    if(autoPlay){
+      mWrapper.createIfNotExist();
+      mWrapper.start();
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.CONTROLS)
+  public void setControls(String controls) {
+    if (TextUtils.equals("controls", controls)) {
+      mWrapper.setControls(true);
+    } else if (TextUtils.equals("nocontrols", controls)) {
+      mWrapper.setControls(false);
+    }
+  }
+
+  private boolean mStopped;
+
+  @WXComponentProp(name = Constants.Name.PLAY_STATUS)
+  public void setPlaystatus(String playstatus) {
+
+    if (mPrepared && !mError && !mStopped) {
+      if (playstatus.equals(Constants.Value.PLAY)) {
+        mWrapper.start();
+      } else if (playstatus.equals(Constants.Value.PAUSE)) {
+        mWrapper.pause();
+      } else if (playstatus.equals(Constants.Value.STOP)) {
+        mWrapper.stopPlayback();
+        mStopped = true;
+      }
+    } else if ((mError || mStopped) && playstatus.equals(Constants.Value.PLAY)) {
+      mError = false;
+      mWrapper.resume();
+
+      mWrapper.getProgressBar().setVisibility(View.VISIBLE);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/WXWeb.java b/android/sdk/src/main/java/org/apache/weex/ui/component/WXWeb.java
new file mode 100644
index 0000000..321c36a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/WXWeb.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.view.View;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.view.IWebView;
+import org.apache.weex.ui.view.WXWebView;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component(lazyload = false)
+
+public class WXWeb extends WXComponent {
+
+    public static final String GO_BACK = "goBack";
+    public static final String GO_FORWARD = "goForward";
+    public static final String RELOAD = "reload";
+    public static final String POST_MESSAGE = "postMessage";
+    protected IWebView mWebView;
+
+    @Deprecated
+    public WXWeb(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+        this(instance, parent, isLazy, basicComponentData);
+    }
+
+    public WXWeb(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+        super(instance, parent, isLazy, basicComponentData);
+        createWebView();
+    }
+
+    protected void createWebView(){
+        String origin = null;
+        try {
+            String bundleUrl = WXSDKManager.getInstance().getSDKInstance(getInstanceId()).getBundleUrl();
+            Uri uri = Uri.parse(bundleUrl);
+            String scheme = uri.getScheme();
+            String authority = uri.getAuthority();
+            if (!TextUtils.isEmpty(scheme) && !TextUtils.isEmpty(authority)) {
+                origin = scheme + "://" + authority;
+            }
+        } catch (Exception e) {
+            // do noting
+        }
+        mWebView = new WXWebView(getContext(), origin);
+    }
+
+    @Override
+    protected View initComponentHostView(@NonNull Context context) {
+        mWebView.setOnErrorListener(new IWebView.OnErrorListener() {
+            @Override
+            public void onError(String type, Object message) {
+                fireEvent(type, message);
+            }
+        });
+        mWebView.setOnPageListener(new IWebView.OnPageListener() {
+            @Override
+            public void onReceivedTitle(String title) {
+                if (getEvents().contains(Constants.Event.RECEIVEDTITLE)) {
+                    Map<String, Object> params = new HashMap<>();
+                    params.put("title", title);
+                    fireEvent(Constants.Event.RECEIVEDTITLE, params);
+                }
+            }
+
+            @Override
+            public void onPageStart(String url) {
+                if (getEvents().contains(Constants.Event.PAGESTART)) {
+                    Map<String, Object> params = new HashMap<>();
+                    params.put("url", url);
+                    fireEvent(Constants.Event.PAGESTART, params);
+                }
+            }
+
+            @Override
+            public void onPageFinish(String url, boolean canGoBack, boolean canGoForward) {
+                if (getEvents().contains(Constants.Event.PAGEFINISH)) {
+                    Map<String, Object> params = new HashMap<>();
+                    params.put("url", url);
+                    params.put("canGoBack", canGoBack);
+                    params.put("canGoForward", canGoForward);
+                    fireEvent(Constants.Event.PAGEFINISH, params);
+                }
+            }
+        });
+        mWebView.setOnMessageListener(new IWebView.OnMessageListener() {
+            @Override
+            public void onMessage(Map<String, Object> params) {
+                fireEvent(Constants.Event.ONMESSAGE, params);
+            }
+        });
+        return mWebView.getView();
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        getWebView().destroy();
+    }
+
+    @Override
+    protected boolean setProperty(String key, Object param) {
+        switch (key) {
+            case Constants.Name.SHOW_LOADING:
+                Boolean result = WXUtils.getBoolean(param,null);
+                if (result != null)
+                    setShowLoading(result);
+                return true;
+            case Constants.Name.SRC:
+                String src = WXUtils.getString(param,null);
+                if (src != null)
+                    setUrl(src);
+                return true;
+            case Constants.Name.SOURCE:
+                String source = WXUtils.getString(param,null);
+                if (source != null)
+                    setSource(source);
+                return true;
+        }
+        return super.setProperty(key,param);
+    }
+
+    @WXComponentProp(name = Constants.Name.SHOW_LOADING)
+    public void setShowLoading(boolean showLoading) {
+        getWebView().setShowLoading(showLoading);
+    }
+
+    @WXComponentProp(name = Constants.Name.SRC)
+    public void setUrl(String url) {
+        if (TextUtils.isEmpty(url) || getHostView() == null) {
+            return;
+        }
+        if (!TextUtils.isEmpty(url)) {
+            loadUrl(getInstance().rewriteUri(Uri.parse(url), URIAdapter.WEB).toString());
+        }
+    }
+
+    @WXComponentProp(name = Constants.Name.SOURCE)
+    public void setSource(String source) {
+        if (!TextUtils.isEmpty(source) && getHostView() != null) {
+            loadDataWithBaseURL(source);
+        }
+    }
+
+    public void setAction(String action, Object data) {
+        if (!TextUtils.isEmpty(action)) {
+            if (action.equals(GO_BACK)) {
+                goBack();
+            } else if (action.equals(GO_FORWARD)) {
+                goForward();
+            } else if (action.equals(RELOAD)) {
+                reload();
+            } else if (action.equals(POST_MESSAGE)) {
+                postMessage(data);
+            }
+        }
+    }
+
+    private void fireEvent(String type, Object message) {
+        if (getEvents().contains(Constants.Event.ERROR)) {
+            Map<String, Object> params = new HashMap<>();
+            params.put("type", type);
+            params.put("errorMsg", message);
+            fireEvent(Constants.Event.ERROR, params);
+        }
+    }
+
+    private void loadUrl(String url) {
+        getWebView().loadUrl(url);
+    }
+
+    private void loadDataWithBaseURL(String source) {
+        getWebView().loadDataWithBaseURL(source);
+    }
+
+    @JSMethod
+    public void reload() {
+        getWebView().reload();
+    }
+
+    @JSMethod
+    public void goForward() {
+        getWebView().goForward();
+    }
+
+    @JSMethod
+    public void goBack() {
+        getWebView().goBack();
+    }
+
+    @JSMethod
+    public void postMessage(Object msg) {
+        getWebView().postMessage(msg);
+    }
+
+    private IWebView getWebView() {
+        return mWebView;
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/basic/WXBasicComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/component/basic/WXBasicComponent.java
new file mode 100644
index 0000000..85b063f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/basic/WXBasicComponent.java
@@ -0,0 +1,231 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.basic;
+
+import android.support.annotation.NonNull;
+import android.view.View;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.action.GraphicPosition;
+import org.apache.weex.ui.action.GraphicSize;
+import org.apache.weex.ui.component.WXComponent;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class WXBasicComponent<T extends View> {
+
+  private Object mExtra;
+  private String mComponentType;
+  private String mRef;
+  private GraphicPosition mLayoutPosition;
+  private GraphicSize mLayoutSize;
+  private boolean mIsLayoutRTL;
+  private BasicComponentData mBasicComponentData;
+
+  private int mViewPortWidth = 750;
+
+  public WXBasicComponent(BasicComponentData basicComponentData) {
+    this.mBasicComponentData = basicComponentData;
+    this.mRef = basicComponentData.mRef;
+    this.mComponentType = basicComponentData.mComponentType;
+  }
+
+  public BasicComponentData getBasicComponentData() {
+    return mBasicComponentData;
+  }
+
+  protected void bindComponent(WXComponent component) {
+    mComponentType = component.getComponentType();
+    mRef = component.getRef();
+  }
+
+  public final @NonNull
+  WXStyle getStyles() {
+    return mBasicComponentData.getStyles();
+  }
+
+  public final @NonNull
+  WXAttr getAttrs() {
+    return mBasicComponentData.getAttrs();
+  }
+
+  public final @NonNull
+  WXEvent getEvents() {
+    return mBasicComponentData.getEvents();
+  }
+
+  /**
+   * Get this node's margin, as defined by cssstyle + default margin.
+   */
+  public final @NonNull
+  CSSShorthand getMargin() {
+    return mBasicComponentData.getMargin();
+  }
+
+  /**
+   * Get this node's padding, as defined by cssstyle + default padding.
+   */
+  public final @NonNull
+  CSSShorthand getPadding() {
+    return mBasicComponentData.getPadding();
+  }
+
+  /**
+   * Get this node's border, as defined by cssstyle.
+   */
+  public @NonNull
+  CSSShorthand getBorder() {
+    return mBasicComponentData.getBorder();
+  }
+
+  public final void setMargins(@NonNull CSSShorthand margins) {
+    mBasicComponentData.setMargins(margins);
+  }
+
+  public final void setPaddings(@NonNull CSSShorthand paddings) {
+    mBasicComponentData.setPaddings(paddings);
+  }
+
+  public final void setBorders(@NonNull CSSShorthand borders) {
+    mBasicComponentData.setBorders(borders);
+  }
+
+  public final void addAttr(Map<String, Object> attrs) {
+    if (attrs == null || attrs.isEmpty()) {
+      return;
+    }
+    mBasicComponentData.addAttr(attrs);
+  }
+
+  public final void addStyle(Map<String, Object> styles) {
+    if (styles == null || styles.isEmpty()) {
+      return;
+    }
+    mBasicComponentData.addStyle(styles);
+  }
+
+  public final void addStyle(Map<String, Object> styles, boolean byPesudo) {
+    if (styles == null || styles.isEmpty()) {
+      return;
+    }
+    mBasicComponentData.addStyle(styles, byPesudo);
+  }
+
+  public final void updateStyle(Map<String, Object> styles, boolean byPesudo){
+    if (styles == null || styles.isEmpty()) {
+      return;
+    }
+    mBasicComponentData.getStyles().updateStyle(styles, byPesudo);
+  }
+
+  public final void addEvent(Set<String> events) {
+    if (events == null || events.isEmpty()) {
+      return;
+    }
+
+    mBasicComponentData.addEvent(events);
+  }
+
+  public final void addShorthand(Map<String, String> shorthand) {
+    if (!shorthand.isEmpty() && mBasicComponentData != null) {
+      mBasicComponentData.addShorthand(shorthand);
+    }
+  }
+
+  public int getViewPortWidth() {
+    return mViewPortWidth;
+  }
+
+  public void setViewPortWidth(int mViewPortWidth) {
+    this.mViewPortWidth = mViewPortWidth;
+  }
+
+  public Object getExtra() {
+    return mExtra;
+  }
+
+  public void updateExtra(Object extra) {
+    this.mExtra = extra;
+  }
+
+  public String getComponentType() {
+    return mComponentType;
+  }
+
+  public String getRef() {
+    return mRef;
+  }
+
+  public void setIsLayoutRTL(boolean isRTL) {
+    mIsLayoutRTL = isRTL;
+  }
+
+  public boolean isLayoutRTL() {
+    return mIsLayoutRTL;
+  }
+
+  public GraphicPosition getLayoutPosition() {
+    if (mLayoutPosition == null) {
+      mLayoutPosition = new GraphicPosition(0, 0, 0, 0);
+    }
+    return mLayoutPosition;
+  }
+
+  protected void setLayoutPosition(GraphicPosition mLayoutPosition) {
+    this.mLayoutPosition = mLayoutPosition;
+  }
+
+  public GraphicSize getLayoutSize() {
+    if (mLayoutSize == null) {
+      mLayoutSize = new GraphicSize(0, 0);
+    }
+    return mLayoutSize;
+  }
+
+  protected void setLayoutSize(GraphicSize mLayoutSize) {
+    this.mLayoutSize = mLayoutSize;
+  }
+
+  public float getCSSLayoutTop() {
+    return mLayoutPosition == null ? 0 : mLayoutPosition.getTop();
+  }
+
+  public float getCSSLayoutBottom() {
+    return mLayoutPosition == null ? 0 : mLayoutPosition.getBottom();
+  }
+
+  public float getCSSLayoutLeft() {
+    return mLayoutPosition == null ? 0 : mLayoutPosition.getLeft();
+  }
+
+  public float getCSSLayoutRight() {
+    return mLayoutPosition == null ? 0 : mLayoutPosition.getRight();
+  }
+
+  public float getLayoutWidth() {
+    return mLayoutSize == null ? 0 : mLayoutSize.getWidth();
+  }
+
+  public float getLayoutHeight() {
+    return mLayoutSize == null ? 0 : mLayoutSize.getHeight();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/binding/AsynLayoutTask.java b/android/sdk/src/main/java/org/apache/weex/ui/component/binding/AsynLayoutTask.java
new file mode 100644
index 0000000..8b9e364
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/binding/AsynLayoutTask.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.binding;
+
+import android.os.AsyncTask;
+
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.list.template.TemplateDom;
+import org.apache.weex.ui.component.list.template.TemplateViewHolder;
+
+/**
+ * Created by furture on 2018/5/11.
+ */
+
+class AsynLayoutTask extends AsyncTask<Void, Void, Void> {
+
+    private final TemplateViewHolder templateViewHolder;
+    private final int position;
+    private final WXComponent component;
+
+    AsynLayoutTask(TemplateViewHolder templateViewHolder, int position, WXComponent component) {
+        this.templateViewHolder = templateViewHolder;
+        this.position = position;
+        this.component = component;
+    }
+
+    @Override
+    protected Void doInBackground(Void... params) {
+        if(templateViewHolder.getHolderPosition() == position){
+            if(component.getInstance() != null && !component.getInstance().isDestroy()) {
+                synchronized (templateViewHolder.getTemplateList()){
+                    if(templateViewHolder.getTemplateList().isDestoryed()){
+                        return null;
+                    }
+                    Layouts.doLayoutOnly(component, templateViewHolder);
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void onPostExecute(Void aVoid) {
+        if(position == templateViewHolder.getHolderPosition()) {
+            if(component.getInstance() != null && !component.getInstance().isDestroy()) {
+                Layouts.setLayout(component, false);
+                if(templateViewHolder.getHolderPosition() >= 0){
+                    templateViewHolder.getTemplateList().fireEvent("_attach_slot", TemplateDom
+                        .findAllComponentRefs(templateViewHolder.getTemplateList().getRef(), position, component));
+                }
+            }
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/binding/Layouts.java b/android/sdk/src/main/java/org/apache/weex/ui/component/binding/Layouts.java
new file mode 100644
index 0000000..2095e02
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/binding/Layouts.java
@@ -0,0 +1,134 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.binding;
+
+
+
+import android.os.AsyncTask;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.component.list.template.TemplateDom;
+import org.apache.weex.ui.component.list.template.TemplateViewHolder;
+import org.apache.weex.ui.component.list.template.WXRecyclerTemplateList;
+import org.apache.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+/**
+ * Created by furture on 2017/8/21.
+ */
+public class Layouts {
+    /**
+     * do dom layout async or sync , and set layout to component on main.
+     * on first use do sync layout, when compontnet reuse do async layout
+     * */
+    public static void doLayoutAsync(final TemplateViewHolder templateViewHolder, boolean async){
+        final WXComponent component = templateViewHolder.getComponent();
+        final  int position = templateViewHolder.getHolderPosition();
+        if(templateViewHolder.asyncTask != null){
+            templateViewHolder.asyncTask.cancel(false);
+            templateViewHolder.asyncTask = null;
+        }
+        if(async){
+            AsyncTask<Void, Void, Void> asyncTask = new AsynLayoutTask(templateViewHolder, position, component);
+            templateViewHolder.asyncTask = asyncTask;
+            asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); //serial executor is better
+        }else{
+            doLayoutOnly(component, templateViewHolder);
+            setLayout(component, false);
+            if(templateViewHolder.getHolderPosition() >= 0){
+                templateViewHolder.getTemplateList().fireEvent("_attach_slot", TemplateDom
+                    .findAllComponentRefs(templateViewHolder.getTemplateList().getRef(), position, component));
+            }
+        }
+
+    }
+    /**
+     * @param layoutHeight height
+     * @param layoutWidth width
+     * */
+    public static void doLayoutSync(WXCell component, float layoutWidth, float layoutHeight){
+        doSafeLayout(component, layoutWidth, layoutHeight);
+        setLayout(component, false);
+    }
+
+        /**
+         * safe layout
+         * */
+    public static void doLayoutOnly(WXComponent component, TemplateViewHolder holder){
+        doSafeLayout(component, holder.getTemplateList().getLayoutWidth(), holder.getTemplateList().getLayoutHeight());
+    }
+
+    private static void doSafeLayout(WXComponent component, float layoutWidth, float layoutHeight){
+        try{
+            long start = System.currentTimeMillis();
+            int height = NativeRenderObjectUtils.nativeLayoutRenderObject(component.getRenderObjectPtr(),
+                    layoutWidth,
+                    layoutHeight);
+            if(WXEnvironment.isOpenDebugLog() && WXRecyclerTemplateList.ENABLE_TRACE_LOG) {
+                WXLogUtils.d(WXRecyclerTemplateList.TAG, "WXTemplateList doSafeLayout " +
+                        component.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE) + " " + Thread.currentThread().getName() + " doSafeLayout  used " +
+                        (System.currentTimeMillis() - start));
+            }
+            if(!(height > 0)){
+                WXLogUtils.e(WXRecyclerTemplateList.TAG, " WXTemplateList doSafeLayout wrong template " +
+                        component.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE)  + " cell height " + height);
+            }
+        }catch (Exception e){
+            if(WXEnvironment.isApkDebugable()){
+                WXLogUtils.e(WXRecyclerTemplateList.TAG, e);
+            }
+        }
+    }
+
+
+    /**
+     * recursive set layout to component,
+     * dom extra will also be updated from dom object to component.
+     * if force is true, always set layout
+     * */
+    public static final void setLayout(WXComponent component, boolean force){
+        if(component.isWaste()){
+            return;
+        }
+        if(component.getAttrs().containsKey(TemplateDom.KEY_RESET_ANIMATION)){
+            if(WXUtils.getBoolean(component.getAttrs().get(TemplateDom.KEY_RESET_ANIMATION), true).booleanValue()){
+                TemplateDom.resetAnimaiton(component.getHostView());
+            }
+        }
+        long ptr = component.getRenderObjectPtr();
+        if(NativeRenderObjectUtils.nativeRenderObjectHasNewLayout(ptr)){
+            NativeRenderObjectUtils.nativeRenderObjectUpdateComponent(ptr, component);
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            int count = container.getChildCount();
+            for (int i = 0; i < count; ++i) {
+                WXComponent child = container.getChild(i);
+                if (child != null) {
+                    setLayout(child, force);
+                }
+            }
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/binding/Statements.java b/android/sdk/src/main/java/org/apache/weex/ui/component/binding/Statements.java
new file mode 100644
index 0000000..5529048
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/binding/Statements.java
@@ -0,0 +1,702 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.binding;
+
+import android.os.Looper;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.bridge.EventResult;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.dom.binding.ELUtils;
+import org.apache.weex.dom.binding.JSONUtils;
+import org.apache.weex.dom.binding.WXStatement;
+import org.apache.weex.el.parse.ArrayStack;
+import org.apache.weex.el.parse.Operators;
+import org.apache.weex.el.parse.Token;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.action.GraphicPosition;
+import org.apache.weex.ui.action.GraphicSize;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXComponentFactory;
+import org.apache.weex.ui.component.WXImage;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.component.list.template.CellDataManager;
+import org.apache.weex.ui.component.list.template.CellRenderContext;
+import org.apache.weex.ui.component.list.template.TemplateDom;
+import org.apache.weex.ui.component.list.template.VirtualComponentLifecycle;
+import org.apache.weex.ui.component.list.template.WXRecyclerTemplateList;
+import org.apache.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by jianbai.gbj on 2017/8/17.
+ * simple statement execute, render component for template list
+ */
+public class Statements {
+
+
+    /**
+     * parse statements token from attrs and style and event
+     * */
+    public static void  parseStatementsToken(WXComponent component){
+        if(component.getBasicComponentData().isRenderPtrEmpty()){
+           component.getBasicComponentData().setRenderObjectPr(component.getRenderObjectPtr());
+        }
+        if(component.getBasicComponentData() != null){
+            BasicComponentData basicComponentData =  component.getBasicComponentData();
+            basicComponentData.getAttrs().parseStatements();
+            basicComponentData.getStyles().parseStatements();
+            basicComponentData.getEvents().parseStatements();
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            int count = container.getChildCount();
+            for (int i = 0; i < count; ++i) {
+                parseStatementsToken(container.getChild(i));
+            }
+        }
+    }
+
+
+
+    /**
+     * init component  if component is lazy,
+     * if component is not lazy, do nothing
+     * */
+    public static void initLazyComponent(WXComponent component, WXVContainer mParent){
+        if(component.isLazy() || component.getHostView() == null){
+            component.lazy(false);
+            if(mParent != null){
+                int index = mParent.indexOf(component);
+                mParent.createChildViewAt(index);
+            }else {
+                component.createView();
+            }
+            component.applyLayoutAndEvent(component);
+            component.bindData(component);
+        }
+    }
+
+
+
+    /**
+     * recursive copy component, none parent connect
+     * */
+    public static WXComponent copyComponentTree(WXComponent component){
+        WXComponent copy =  copyComponentTree(component, component.getParent());
+        return copy;
+    }
+
+    /**
+     * recursive copy component,
+     * */
+    private static final WXComponent copyComponentTree(WXComponent source, WXVContainer parent){
+        BasicComponentData basicComponentData = null;
+        try {
+            basicComponentData = source.getBasicComponentData().clone();
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+        }
+        WXComponent component = WXComponentFactory
+            .newInstance(source.getInstance(), parent, basicComponentData);
+        GraphicPosition graphicPosition = source.getLayoutPosition();
+        GraphicSize graphicSize = source.getLayoutSize();
+        component.updateDemission(graphicPosition.getTop(), graphicPosition.getBottom(), graphicPosition.getLeft(), graphicPosition.getRight(),
+                 graphicSize.getHeight(), graphicSize.getWidth());
+        component.updateExtra(source.getExtra());
+        if(source instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) source;
+            WXVContainer childParent = (WXVContainer) component;
+            int count = container.getChildCount();
+            for (int i = 0; i < count; ++i) {
+                WXComponent sourceChild = container.getChild(i);
+                if (sourceChild != null) {
+                    WXComponent targetChild = copyComponentTree(sourceChild,  childParent);childParent.addChild(targetChild);
+                    NativeRenderObjectUtils.nativeAddChildRenderObject(childParent.getRenderObjectPtr(),
+                            targetChild.getRenderObjectPtr());
+                }
+            }
+        }
+        //copy info need be sync
+        if(source.isWaste()){
+            component.setWaste(true);
+        }
+        return  component;
+    }
+
+    /**
+     *  @param component component with v-for statement, v-if statement and bind attrs
+     *  @param stack  execute context
+     *  render component in context, the function do the following  work.
+     *  execute component's v-for statement, v-if statement in context,
+     *  and rebuild component's tree with the statement, v-for reuse component execute by pre render.
+     *  if executed, component will be removed, don't remove, just mark it waste;
+     *  may be next render it can be used.
+     *  after statement has executed, render component's binding attrs in context and bind it to component.
+     * */
+    public static final List<WXComponent> doRender(WXComponent component, CellRenderContext stack){
+        List<WXComponent> updates = new ArrayList<>(4);
+        try{
+            doRenderComponent(component, stack, updates);
+        }catch (Exception e){
+            WXLogUtils.e("WeexStatementRender", e);
+        }
+        return updates;
+    }
+
+    public static final void doInitCompontent(List<WXComponent> updates) {
+        if(updates == null || updates.size() == 0){
+            return;
+        }
+        for(WXComponent renderNode : updates){
+            if(renderNode.getParent() == null){
+                throw new IllegalArgumentException("render node parent cann't find");
+            }
+            WXVContainer parent = renderNode.getParent();
+            int renderIndex = parent.indexOf(renderNode);
+            if(renderIndex < 0){
+                throw new IllegalArgumentException("render node cann't find");
+            }
+            parent.createChildViewAt(renderIndex);
+            renderNode.applyLayoutAndEvent(renderNode);
+            renderNode.bindData(renderNode);
+        }
+    }
+
+        /**
+         *  @param component component with v-for statement, v-if statement and bind attrs
+         *  @param context   execute context
+         *  render component in context, the function do the following  work.
+         *  execute component's v-for statement, v-if statement in context,
+         *  and rebuild component's tree with the statement, v-for reuse component execute by pre render.
+         *  if executed, component will be removed, don't remove, just mark it waste;
+         *  may be next render it can be used.
+         *  after statement has executed, render component's binding attrs in context and bind it to component.
+         * */
+    private static final int doRenderComponent(WXComponent component, CellRenderContext context,
+                                               List<WXComponent> updates){
+        WXVContainer parent = component.getParent();
+        WXAttr attrs = component.getAttrs();
+        WXStatement statement =  attrs.getStatement();
+        if(statement != null){
+            Token vif =  null;
+            JSONObject vfor = null;
+            if(statement.get(WXStatement.WX_IF) instanceof Token){
+                vif = (Token) statement.get(WXStatement.WX_IF);
+            }
+            if(statement.get(WXStatement.WX_FOR) instanceof  JSONObject){
+                vfor = (JSONObject) statement.get(WXStatement.WX_FOR);
+            }
+            // execute v-for content
+            if(vfor != null){
+                int    renderIndex = parent.indexOf(component);
+                if(vfor.get(WXStatement.WX_FOR_LIST) instanceof Token){
+                    Token listBlock = (Token) vfor.get(WXStatement.WX_FOR_LIST);
+                    String indexKey = vfor.getString(WXStatement.WX_FOR_INDEX);
+                    String itemKey = vfor.getString(WXStatement.WX_FOR_ITEM);
+                    Object data = null;
+                    if(listBlock != null) {
+                        data = listBlock.execute(context.stack);
+                    }
+                    if((data instanceof List || data instanceof  Map)){
+
+                        Collection collection = null;
+                        Map  map = null;
+                        if(data instanceof  List){
+                            collection = (List)data;
+                        }else{
+                            map = (Map)data;
+                            collection = map.keySet();
+                        }
+                        Map<String, Object> loop = new HashMap<>();
+                        int index = 0;
+                        for(Object item : collection){
+                            Object key = null;
+                            Object value = item;
+                            if(map == null){
+                                key = index;
+                                value = item;
+                                index ++;
+                            }else{
+                                key = item;
+                                value = map.get(item);
+                            }
+                            if(indexKey != null){
+                                loop.put(indexKey, key);
+                            }
+
+                            if(itemKey != null){
+                                loop.put(itemKey, value);
+                            }else{
+                                context.stack.push(value);
+                            }
+                            if(loop.size() > 0){
+                                context.stack.push(loop);
+                            }
+
+
+                            if(vif != null){
+                                if(!Operators.isTrue(vif.execute(context.stack))){
+                                    continue;
+                                }
+                            }
+                            //find resuable renderNode
+                            WXComponent renderNode = null;
+                            if(renderIndex < parent.getChildCount()){
+                                renderNode = parent.getChild(renderIndex);
+                                //check is same statment, if true, it is usabled.
+                                if(!isCreateFromNodeStatement(renderNode, component)){
+                                    renderNode = null;
+                                }
+                                if(renderNode != null){
+                                    if(renderNode.isWaste()){
+                                        renderNode.setWaste(false);
+                                    }
+                                }
+                            }
+                            //none resuable render node, create node, add to parent, but clear node's statement
+                            if(renderNode == null){
+                                long start = System.currentTimeMillis();
+                                renderNode = copyComponentTree(component, parent);
+                                renderNode.setWaste(false);
+                                if(renderNode.getAttrs().getStatement() != null) {
+                                    renderNode.getAttrs().getStatement().remove(WXStatement.WX_FOR);
+                                    renderNode.getAttrs().getStatement().remove(WXStatement.WX_IF); //clear node's statement
+                                }
+                                parent.addChild(renderNode, renderIndex);
+                                NativeRenderObjectUtils.nativeAddChildRenderObject(parent.getRenderObjectPtr(),
+                                        renderNode.getRenderObjectPtr());
+                                updates.add(renderNode);
+                                if(WXEnvironment.isApkDebugable()){
+                                    WXLogUtils.d(WXRecyclerTemplateList.TAG, Thread.currentThread().getName() +  renderNode.getRef() + renderNode.getComponentType() + "statements copy component tree used " + (System.currentTimeMillis() - start));
+                                }
+                            }
+                            doBindingAttrsEventAndRenderChildNode(renderNode, context, updates);
+                            renderIndex++;
+                            if(loop.size() > 0){
+                                context.stack.push(loop);
+                            }
+                            if(itemKey == null) {
+                                context.stack.pop();
+                            }
+                        }
+                    }
+                }else{
+                    WXLogUtils.e(WXRecyclerTemplateList.TAG,  vfor.toJSONString() + " not call vfor block, for pre compile");
+                }
+                //after v-for execute, remove component created pre v-for.
+                for(;renderIndex<parent.getChildCount(); renderIndex++){
+                    WXComponent wasteNode = parent.getChild(renderIndex);
+                    if(!isCreateFromNodeStatement(wasteNode, component)){
+                        break;
+                    }
+                    wasteNode.setWaste(true);
+                }
+                return renderIndex - parent.indexOf(component);
+            }
+
+            //execute v-if context
+            if(vif != null){
+                if(!Operators.isTrue(vif.execute(context.stack))){
+                    component.setWaste(true);
+                    return 1;
+                }else{
+                    component.setWaste(false);
+                }
+
+            }
+        }
+        doBindingAttrsEventAndRenderChildNode(component, context, updates);
+        return  1;
+    }
+
+
+    /**
+     * bind attrs and doRender component child
+     * */
+    private static void doBindingAttrsEventAndRenderChildNode(WXComponent component, CellRenderContext context,
+                                                              List<WXComponent> updates){
+        WXAttr attr = component.getAttrs();
+
+        /**
+         * sub component supported, sub component new stack
+         * */
+        ArrayStack stack = context.stack;
+
+
+        String virtualComponentId = null;
+        boolean callVirtualComponentAttach = false;
+        if(attr.get(ELUtils.IS_COMPONENT_ROOT) != null
+                && WXUtils.getBoolean(attr.get(ELUtils.IS_COMPONENT_ROOT), false)){
+            if(attr.get(ELUtils.COMPONENT_PROPS) != null
+                    && JSONUtils.isJSON(attr.get(ELUtils.COMPONENT_PROPS))){
+                 String compoentId = (String) attr.get(CellDataManager.SUB_COMPONENT_TEMPLATE_ID);
+                Object compoentData = null;
+                if(!TextUtils.isEmpty(compoentId)){
+                   virtualComponentId =  context.getRenderState().getVirtualComponentIds().get(component.getViewTreeKey());
+                   if(virtualComponentId == null){ //none virtualComponentId, create and do attach
+                        virtualComponentId =  CellDataManager.createVirtualComponentId(context.templateList.getRef(),
+                                component.getViewTreeKey(), context.templateList.getItemId(context.position));
+                        Map<String, Object>  props  = renderProps(JSONUtils.toJSON(attr.get(ELUtils.COMPONENT_PROPS)), context.stack);
+                        EventResult result = WXBridgeManager.getInstance().syncCallJSEventWithResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, compoentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.CREATE,  new Object[]{
+                                virtualComponentId,
+                                props
+                        }, null);
+                        if(result != null
+                                && result.getResult() != null
+                                && result.getResult() instanceof Map){
+                            props.putAll((Map<? extends String, ?>) result.getResult());
+                        }
+                        compoentData  =  props;
+                        context.getRenderState().getVirtualComponentIds().put(component.getViewTreeKey(), virtualComponentId);
+                        context.templateList.getCellDataManager().createVirtualComponentData(context.position, virtualComponentId, compoentData);
+                         callVirtualComponentAttach = true; // when first create virtual compoent, call create
+                     }else{ // get virtual component data check has dirty's update
+                       compoentData = context.getRenderState().getVirtualComponentDatas().get(virtualComponentId);
+                       if(context.getRenderState().isHasDataUpdate()){
+                           Map<String, Object>  props  = renderProps((JSONObject) attr.get(ELUtils.COMPONENT_PROPS), context.stack);
+                           EventResult result = WXBridgeManager.getInstance().syncCallJSEventWithResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.SYNSTATE,  new Object[]{
+                                   virtualComponentId,
+                                   props
+                           }, null);
+
+                           if(result != null
+                                   && result.getResult() != null
+                                   && result.getResult() instanceof Map){
+                               props.putAll((Map<? extends String, ?>) result.getResult());
+                               context.templateList.getCellDataManager().updateVirtualComponentData(virtualComponentId, props);
+                               compoentData = props;
+                           }
+                       }
+                    }
+                    component.getAttrs().put(CellDataManager.VIRTUAL_COMPONENT_ID, virtualComponentId);
+                }else{ //stateless component
+                    Map<String, Object>  props  = renderProps((JSONObject) attr.get(ELUtils.COMPONENT_PROPS), context.stack);
+                    compoentData = props;
+                }
+                //virtual component is new context
+                context.stack = new ArrayStack();
+                if(compoentData != null){
+                    context.stack.push(compoentData);
+                }
+            }
+        }
+
+        /**
+         * check node is render only once, if render once, and has rendered, just return
+         * */
+        Object vonce = null;
+        if(attr.getStatement() != null){
+            vonce = attr.getStatement().get(WXStatement.WX_ONCE);
+        }
+        if(vonce != null){
+            ArrayStack onceStack = context.getRenderState().getOnceComponentStates().get(component.getViewTreeKey());
+            if(onceStack == null){
+                onceStack = context.templateList.copyStack(context, stack);
+                context.getRenderState().getOnceComponentStates().put(component.getViewTreeKey(), onceStack);
+            }
+            context.stack = onceStack;
+        }
+
+        doRenderBindingAttrsAndEvent(component, context);
+        if(component instanceof WXVContainer){
+            if(component.isWaste()){
+                if(!(component instanceof WXCell)){
+                     return;
+                }
+            }
+            WXVContainer container = (WXVContainer) component;
+            for(int k=0; k<container.getChildCount();){
+                WXComponent next = container.getChild(k);
+                k += doRenderComponent(next, context, updates);
+            }
+        }
+        if(stack != context.stack){
+            context.stack = stack;
+        }
+        //create virtual componentId
+        if(callVirtualComponentAttach && virtualComponentId != null){
+            WXBridgeManager.getInstance().asyncCallJSEventVoidResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC, component.getInstanceId(), null, virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.ATTACH, new Object[]{
+                    TemplateDom.findAllComponentRefs(context.templateList.getRef(),context.position, component)
+            });
+        }
+     }
+
+
+    /**
+     * check whether render node is create from component node statement.
+     * */
+    private static boolean isCreateFromNodeStatement(WXComponent renderNode, WXComponent component){
+        return (renderNode.getRef() != null && renderNode.getRef().equals(component.getRef()));
+    }
+
+
+    /**
+     * render dynamic binding attrs and bind them to component node.
+     * */
+    private static void doRenderBindingAttrsAndEvent(WXComponent component, CellRenderContext context){
+        ArrayStack stack  = context.stack;
+        component.setWaste(false);
+        WXAttr attr = component.getAttrs();
+        if(attr != null
+                && attr.getBindingAttrs() != null
+                && attr.getBindingAttrs().size() > 0){
+            ArrayMap<String, Object> bindAttrs = component.getAttrs().getBindingAttrs();
+            Map<String, Object> dynamic =  renderBindingAttrs(bindAttrs, stack);
+            Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
+            /**
+             * diff attrs, see attrs has update, remove none update attrs
+             * */
+            Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
+            while (iterator.hasNext()){
+                Map.Entry<String, Object> entry = iterator.next();
+                String key = entry.getKey();
+                Object value = entry.getValue();
+                Object oldValue = attr.get(key);
+                if(value == null){
+                    if(oldValue == null){
+                        iterator.remove();
+                        continue;
+                    }
+                }else{
+                    if(value.equals(oldValue)){
+                        iterator.remove();
+                    }
+                }
+            }
+
+            if(dynamic.size() > 0) {
+                if(dynamic.size() == 1
+                        && dynamic.get(Constants.Name.SRC) != null
+                        && component instanceof WXImage){
+                    //for image avoid dirty layout, only update src attrs
+                    component.getAttrs().put(Constants.Name.SRC, dynamic.get(Constants.Name.SRC));
+                }else {
+                    component.nativeUpdateAttrs(dynamic);
+                }
+                if(isMainThread()) {
+                    component.updateProperties(dynamic);
+                }
+                dynamic.clear();
+            }
+        }
+
+
+        WXStyle style = component.getStyles();
+        if(style != null && style.getBindingStyle() != null){
+            ArrayMap<String, Object> bindStyle = style.getBindingStyle();
+            Map<String, Object> dynamic =  renderBindingAttrs(bindStyle, stack);
+            Set<Map.Entry<String, Object>> entries = dynamic.entrySet();
+            /**
+             * diff attrs, see attrs has update, remove none update attrs
+             * */
+            Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
+            while (iterator.hasNext()){
+                Map.Entry<String, Object> entry = iterator.next();
+                String key = entry.getKey();
+                Object value = entry.getValue();
+                Object oldValue = style.get(key);
+                if(value == null){
+                    if(oldValue == null){
+                        iterator.remove();
+                        continue;
+                    }
+                }else{
+                    if(value.equals(oldValue)){
+                        iterator.remove();
+                    }
+                }
+            }
+            if(dynamic.size() > 0) {
+                  component.updateNativeStyles(dynamic);
+                 if(isMainThread()) {
+                    component.updateProperties(dynamic);
+                 }
+            }
+        }
+
+        WXEvent event = component.getEvents();
+        if(event == null || event.getEventBindingArgs() == null){
+            return;
+        }
+        Set<Map.Entry<String, Object>> eventBindArgsEntrySet = event.getEventBindingArgs().entrySet();
+        for(Map.Entry<String, Object> eventBindArgsEntry : eventBindArgsEntrySet){
+             List<Object> values = getBindingEventArgs(stack, eventBindArgsEntry.getValue());
+             if(values != null){
+                 event.putEventBindingArgsValue(eventBindArgsEntry.getKey(), values);
+             }
+        }
+
+    }
+
+
+    /**
+     * @param  bindAttrs  none null,
+     * @param  context  context
+     * return binding attrs rended value in context
+     * */
+    private static final  ThreadLocal<Map<String, Object>> dynamicLocal = new ThreadLocal<>();
+    public static Map<String, Object> renderBindingAttrs(ArrayMap bindAttrs, ArrayStack stack){
+        Set<Map.Entry<String, Object>> entrySet = bindAttrs.entrySet();
+        Map<String, Object> dynamic = dynamicLocal.get();
+        if(dynamic == null) {
+            dynamic = new HashMap<>();
+            dynamicLocal.set(dynamic);
+        }
+        if(dynamic.size() > 0){
+            dynamic.clear();
+        }
+        for(Map.Entry<String, Object> entry : entrySet){
+            Object value = entry.getValue();
+            String key = entry.getKey();
+            if(value instanceof  JSONObject
+                    && (((JSONObject) value).get(ELUtils.BINDING)  instanceof Token)){
+                JSONObject binding = (JSONObject) value;
+                Token block = (Token) (binding.get(ELUtils.BINDING));
+                Object blockValue = block.execute(stack);
+                dynamic.put(key, blockValue);
+            }else if(value instanceof JSONArray){
+                JSONArray array = (JSONArray) value;
+                StringBuilder builder = new StringBuilder();
+                for(int i=0; i<array.size(); i++){
+                    Object element = array.get(i);
+                    if(element instanceof  CharSequence){
+                        builder.append(element);
+                        continue;
+                    }
+                    if(element instanceof JSONObject
+                            && (((JSONObject) element).get(ELUtils.BINDING) instanceof Token)){
+                        JSONObject binding = (JSONObject) element;
+                        Token block = (Token) (binding.get(ELUtils.BINDING));
+                        Object blockValue = block.execute(stack);
+                        if(blockValue == null){
+                            blockValue = "";
+                        }
+                        builder.append(blockValue);
+                    }
+                }
+                String builderString = builder.toString();
+                if(builderString.length() > 256){
+                    if(WXEnvironment.isApkDebugable()){
+                        WXLogUtils.w(WXRecyclerTemplateList.TAG, " warn too big string " + builderString);
+                    }
+                }
+                dynamic.put(key, builderString);
+            }
+        }
+        return  dynamic;
+    }
+
+
+    public static Map<String, Object> renderProps(JSONObject props, ArrayStack stack){
+        Set<Map.Entry<String, Object>> entrySet = props.entrySet();
+        Map<String, Object> renderProps = new ArrayMap<>(4);
+        for(Map.Entry<String, Object> entry : entrySet){
+            Object value = entry.getValue();
+            String key = entry.getKey();
+            if(value instanceof  JSONObject
+                    && (((JSONObject) value).get(ELUtils.BINDING)  instanceof Token)){
+                JSONObject binding = (JSONObject) value;
+                Token block = (Token) (binding.get(ELUtils.BINDING));
+                Object blockValue = block.execute(stack);
+                renderProps.put(key, blockValue);
+            }else{
+                renderProps.put(key, value);
+            }
+        }
+        return  renderProps;
+    }
+
+    public static List<Object> getBindingEventArgs(ArrayStack stack, Object bindings){
+          List<Object>  params = new ArrayList<>(4);
+          if(bindings instanceof  JSONArray){
+              JSONArray array = (JSONArray) bindings;
+              for(int i=0; i<array.size(); i++){
+                  Object value = array.get(i);
+                  if(value instanceof  JSONObject
+                          && (((JSONObject) value).get(ELUtils.BINDING) instanceof Token)){
+                      Token block = (Token)(((JSONObject) value).get(ELUtils.BINDING));
+                      Object blockValue = block.execute(stack);
+                      params.add(blockValue);
+                  }else{
+                      params.add(value);
+                  }
+              }
+          }else if(bindings instanceof  JSONObject){
+              JSONObject binding = (JSONObject) bindings;
+               if(binding.get(ELUtils.BINDING) instanceof Token){
+                   Token block = (Token) binding.get(ELUtils.BINDING);
+                   Object blockValue = block.execute(stack);
+                   params.add(blockValue);
+               }else{
+                   params.add(bindings.toString());
+               }
+          }else{
+              params.add(bindings.toString());
+          }
+          return  params;
+    }
+
+
+    private static boolean isMainThread(){
+        return  Thread.currentThread() == Looper.getMainLooper().getThread();
+    }
+
+
+
+    public static String getComponentId(WXComponent component){
+        if(component instanceof WXCell || component == null){
+            return  null;
+        }
+        WXAttr attr = component.getAttrs();
+        if(attr.get(ELUtils.IS_COMPONENT_ROOT) != null
+                && WXUtils.getBoolean(attr.get(ELUtils.IS_COMPONENT_ROOT), false)){
+            if(attr.get(ELUtils.COMPONENT_PROPS) != null
+                    && attr.get(ELUtils.COMPONENT_PROPS) instanceof  JSONObject){
+                Object componentId = attr.get(CellDataManager.VIRTUAL_COMPONENT_ID);
+                if(componentId == null){
+                    return null;
+                }
+                return componentId.toString();
+            }
+        }
+        return getComponentId(component.getParent());
+    }
+
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/helper/ScrollStartEndHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/ScrollStartEndHelper.java
new file mode 100644
index 0000000..339c267
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/ScrollStartEndHelper.java
@@ -0,0 +1,153 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.helper;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.OnWXScrollListener;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXScroller;
+import org.apache.weex.ui.component.list.BasicListComponent;
+import org.apache.weex.ui.component.list.ListComponentView;
+import org.apache.weex.ui.component.list.template.WXRecyclerTemplateList;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.Map;
+
+
+/**
+ * Created by furture on 2017/11/13.
+ */
+
+public class ScrollStartEndHelper implements Runnable{
+
+    private Handler handler;
+    private WXComponent component;
+    private boolean  hasStart;
+    private boolean  canStart = false;
+
+    private long  minInterval;
+    private int oldState = OnWXScrollListener.IDLE;
+
+    private int x;
+    private int y;
+    private boolean hasScrollEnd;
+
+
+    public ScrollStartEndHelper(WXComponent component) {
+        this.component = component;
+        this.handler = new Handler(Looper.getMainLooper());
+        this.minInterval = WXUtils.getNumberInt(component.getAttrs().get("minscrolldelayinterval"), 32);
+    }
+
+    /**
+     * @param  x scroll offset or dx, which is not accurate
+     * @param  y scroll offset or dy, which is not accurate
+     * */
+    public void  onScrolled(int x, int y){
+        if((component.getEvents().contains(Constants.Event.SCROLL_START)
+                || component.getEvents().contains(Constants.Event.SCROLL_END))){
+            this.x = x;
+            this.y = y;
+            if(!hasStart && canStart){
+                if(component.getEvents().contains(Constants.Event.SCROLL_START)){
+                    Map<String, Object> event = getScrollEvent(x,y);
+                    if (null !=event && !event.isEmpty()){
+                        component.fireEvent(Constants.Event.SCROLL_START,event);
+
+                    }
+                }
+                hasStart = true;
+                canStart = false;
+            }
+            handler.removeCallbacks(this);
+            handler.postDelayed(this, minInterval);
+        }
+    }
+
+
+    @Override
+    public void run() {
+        if(component.isDestoryed()){
+            return;
+        }
+        if(!hasScrollEnd){
+            return;
+        }
+        if(canStart){
+            component.fireEvent(Constants.Event.SCROLL_START, getScrollEvent(this.x, this.y));
+            canStart = false;
+        }
+        if(component.getEvents().contains(Constants.Event.SCROLL_END)){
+            component.fireEvent(Constants.Event.SCROLL_END, getScrollEvent(this.x, this.y));
+
+        }
+        hasStart = false;
+        hasScrollEnd = false;
+
+    }
+
+    private Map<String, Object> getScrollEvent(int offsetX, int offsetY){
+        if(component instanceof BasicListComponent){
+            BasicListComponent basicListComponent = (BasicListComponent) component;
+            if(basicListComponent.getHostView() instanceof ListComponentView){
+                ListComponentView componentView = (ListComponentView) basicListComponent.getHostView();
+                if(componentView != null){
+                    return basicListComponent.getScrollEvent(componentView.getInnerView(), offsetX, offsetY);
+                }
+            }
+        }else if(component instanceof WXRecyclerTemplateList){
+            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) component;
+            return templateList.getScrollEvent(templateList.getHostView().getInnerView(), offsetX, offsetY);
+        }else if(component instanceof WXScroller){
+            WXScroller scroller = (WXScroller) component;
+            return scroller.getScrollEvent(offsetX, offsetY);
+        }
+        return null;
+    }
+
+    public void onScrollStateChanged(int newState){
+
+        if(oldState == OnWXScrollListener.IDLE){
+            canStart = true;
+        }
+
+        if(newState == OnWXScrollListener.IDLE){
+            hasScrollEnd = true;
+            handler.removeCallbacks(this);
+            handler.postDelayed(this, minInterval);
+        }
+
+        oldState = newState;
+    }
+
+
+    public static boolean isScrollEvent(String type){
+        if(Constants.Event.SCROLL.equals(type)){
+            return  true;
+        }else if(Constants.Event.SCROLL_START.equals(type)){
+            return  true;
+        }else if(Constants.Event.SCROLL_END.equals(type)){
+            return  true;
+        }
+        return  false;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/helper/SoftKeyboardDetector.java b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/SoftKeyboardDetector.java
new file mode 100644
index 0000000..b524e16
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/SoftKeyboardDetector.java
@@ -0,0 +1,148 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.helper;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by moxun on 17/3/24.
+ */
+
+public class SoftKeyboardDetector {
+
+    private static final int KEYBOARD_VISIBLE_THRESHOLD_DIP = 100;
+
+    public static Unregister registerKeyboardEventListener(Activity activity, final OnKeyboardEventListener listener) {
+        if (activity == null || listener == null) {
+            WXLogUtils.e("Activity or listener is null!");
+            return null;
+        }
+
+        if (activity.getWindow() != null) {
+            WindowManager.LayoutParams attributes = activity.getWindow().getAttributes();
+            if (attributes != null) {
+                int softInputMode = attributes.softInputMode;
+                if (softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
+                        || softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) {
+                    WXLogUtils.e("SoftKeyboard detector can't work with softInputMode is SOFT_INPUT_ADJUST_NOTHING or SOFT_INPUT_ADJUST_PAN");
+                    return null;
+                }
+            }
+        }
+
+        final View activityRoot = getActivityRoot(activity);
+
+        if (activityRoot == null) {
+            WXLogUtils.e("Activity root is null!");
+            return null;
+        }
+
+        final ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+
+            private final Rect visibleFrame = new Rect();
+            private final int threshold = WXViewUtils.dip2px(KEYBOARD_VISIBLE_THRESHOLD_DIP);
+            private boolean wasKeyboardOpened = false;
+
+            @Override
+            public void onGlobalLayout() {
+                activityRoot.getWindowVisibleDisplayFrame(visibleFrame);
+                int heightDiff = activityRoot.getRootView().getHeight() - visibleFrame.height();
+                boolean isOpen = heightDiff > threshold;
+                if (isOpen == wasKeyboardOpened) {
+                    return;
+                }
+
+                wasKeyboardOpened = isOpen;
+                listener.onKeyboardEvent(isOpen);
+            }
+        };
+
+        activityRoot.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
+        return new DefaultUnRegister(activity, layoutListener);
+    }
+
+    public static boolean isKeyboardVisible(Activity activity) {
+        Rect windowFrame = new Rect();
+        View root = getActivityRoot(activity);
+
+        if (root != null) {
+            root.getWindowVisibleDisplayFrame(windowFrame);
+            int heightDiff = root.getRootView().getHeight() - windowFrame.height();
+            return heightDiff > WXViewUtils.dip2px(KEYBOARD_VISIBLE_THRESHOLD_DIP);
+        }
+        return false;
+    }
+
+    public static @Nullable View getActivityRoot(Activity activity) {
+        if (activity != null) {
+            return activity.findViewById(android.R.id.content);
+        }
+        return null;
+    }
+
+    public static final class DefaultUnRegister implements Unregister {
+
+        private WeakReference<Activity> activityRef;
+        private WeakReference<ViewTreeObserver.OnGlobalLayoutListener> listenerRef;
+
+        public DefaultUnRegister(Activity activity, ViewTreeObserver.OnGlobalLayoutListener listener) {
+            this.activityRef = new WeakReference<>(activity);
+            this.listenerRef = new WeakReference<>(listener);
+        }
+
+        @Override
+        public void execute() {
+            Activity activity = activityRef.get();
+            ViewTreeObserver.OnGlobalLayoutListener listener = listenerRef.get();
+
+            if (activity != null && listener != null) {
+                View root = SoftKeyboardDetector.getActivityRoot(activity);
+                if (root != null) {
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                        root.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
+                    } else {
+                        root.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
+                    }
+                }
+            }
+
+            activityRef.clear();
+            listenerRef.clear();
+        }
+    }
+
+    public interface Unregister {
+        void execute();
+    }
+
+    public interface OnKeyboardEventListener {
+        void onKeyboardEvent(boolean isShown);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/helper/WXStickyHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/WXStickyHelper.java
new file mode 100644
index 0000000..58b1d94
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/WXStickyHelper.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.helper;
+
+import org.apache.weex.ui.component.Scrollable;
+import org.apache.weex.ui.component.WXComponent;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Created by miomin on 16/7/7.
+ */
+public class WXStickyHelper {
+
+    private Scrollable scrollable;
+
+    public WXStickyHelper(Scrollable scrollable) {
+        this.scrollable = scrollable;
+    }
+
+    public void bindStickStyle(WXComponent component, Map<String, Map<String, WXComponent>> mStickyMap) {
+        Scrollable scroller = component.getParentScroller();
+        if (scroller == null) {
+            return;
+        }
+        Map<String, WXComponent> stickyMap = mStickyMap.get(scroller
+                .getRef());
+        if (stickyMap == null) {
+            stickyMap = new ConcurrentHashMap<>();
+        }
+        if (stickyMap.containsKey(component.getRef())) {
+            return;
+        }
+        stickyMap.put(component.getRef(), component);
+        mStickyMap.put(scroller.getRef(), stickyMap);
+    }
+
+    public void unbindStickStyle(WXComponent component, Map<String, Map<String, WXComponent>> mStickyMap) {
+        Scrollable scroller = component.getParentScroller();
+        if (scroller == null) {
+            return;
+        }
+        Map<String, WXComponent> stickyMap = mStickyMap.get(scroller
+                .getRef());
+        if (stickyMap == null) {
+            return;
+        }
+        stickyMap.remove(component.getRef());
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/helper/WXTimeInputHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/WXTimeInputHelper.java
new file mode 100644
index 0000000..600fde7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/helper/WXTimeInputHelper.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.helper;
+
+import android.support.annotation.Nullable;
+import android.widget.TextView;
+
+import org.apache.weex.appfram.pickers.DatePickerImpl;
+import org.apache.weex.ui.component.AbstractEditComponent;
+
+/**
+ * Created by moxun on 16/10/12.
+ */
+
+public class WXTimeInputHelper {
+  public static void pickDate(String max, String min, final AbstractEditComponent component) {
+    final TextView target = component.getHostView();
+
+    DatePickerImpl.pickDate(
+            target.getContext(),
+            target.getText().toString(),
+            max,
+            min,
+            new DatePickerImpl.OnPickListener() {
+              @Override
+              public void onPick(boolean set, @Nullable String result) {
+                if (set) {
+                  target.setText(result);
+                  component.performOnChange(result);
+                }
+              }
+            },
+            null);
+  }
+
+  public static void pickTime(final AbstractEditComponent component) {
+    final TextView target = component.getHostView();
+
+    DatePickerImpl.pickTime(
+            target.getContext(),
+            target.getText().toString(),
+            new DatePickerImpl.OnPickListener() {
+              @Override
+              public void onPick(boolean set, @Nullable String result) {
+                if (set) {
+                  target.setText(result);
+                  component.performOnChange(result);
+                }
+              }
+            },
+            null
+    );
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/BasicListComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/BasicListComponent.java
new file mode 100644
index 0000000..d4b8f52
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/BasicListComponent.java
@@ -0,0 +1,1477 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.text.TextUtils;
+import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.ICheckBindingScroller;
+import org.apache.weex.common.OnWXScrollListener;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.AppearanceHelper;
+import org.apache.weex.ui.component.Scrollable;
+import org.apache.weex.ui.component.WXBaseRefresh;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXComponentProp;
+import org.apache.weex.ui.component.WXHeader;
+import org.apache.weex.ui.component.WXLoading;
+import org.apache.weex.ui.component.WXRefresh;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.component.helper.ScrollStartEndHelper;
+import org.apache.weex.ui.component.helper.WXStickyHelper;
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+import org.apache.weex.ui.view.listview.adapter.IOnLoadMoreListener;
+import org.apache.weex.ui.view.listview.adapter.IRecyclerAdapterListener;
+import org.apache.weex.ui.view.listview.adapter.ListBaseViewHolder;
+import org.apache.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
+import org.apache.weex.ui.view.listview.adapter.WXRecyclerViewOnScrollListener;
+import org.apache.weex.ui.view.refresh.wrapper.BounceRecyclerView;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * Created by sospartan on 13/12/2016.
+ */
+
+public abstract class BasicListComponent<T extends ViewGroup & ListComponentView> extends
+    WXVContainer<T> implements
+    IRecyclerAdapterListener<ListBaseViewHolder>, IOnLoadMoreListener, Scrollable {
+  public static final String TRANSFORM = "transform";
+  public static final String LOADMOREOFFSET = "loadmoreoffset";
+  private String TAG = "BasicListComponent";
+  private int mListCellCount = 0;
+  private boolean mForceLoadmoreNextTime = false;
+  private static final Pattern transformPattern = Pattern.compile("([a-z]+)\\(([0-9\\.]+),?([0-9\\.]+)?\\)");
+
+  private Map<String, AppearanceHelper> mAppearComponents = new HashMap<>();
+  private Runnable mAppearChangeRunnable = null;
+  private long mAppearChangeRunnableDelay = 50;
+
+  private boolean isScrollable = true;
+  private ArrayMap<String, Long> mRefToViewType;
+  private SparseArray<ArrayList<WXComponent>> mViewTypes;
+  private WXRecyclerViewOnScrollListener mViewOnScrollListener = new WXRecyclerViewOnScrollListener(this);
+
+  private static final int MAX_VIEWTYPE_ALLOW_CACHE = 9;
+  private static boolean mAllowCacheViewHolder = true;
+  private static boolean mDownForBidCacheViewHolder = false;
+
+
+  protected int mLayoutType = WXRecyclerView.TYPE_LINEAR_LAYOUT;
+  protected int mColumnCount = 1;
+  protected float mColumnGap = 0;
+  protected float mColumnWidth = 0;
+  protected float mLeftGap = 0;
+  protected float mRightGap = 0;
+
+  private int mOffsetAccuracy = 10;
+  private Point mLastReport = new Point(-1, -1);
+  private boolean mHasAddScrollEvent = false;
+
+  private RecyclerView.ItemAnimator mItemAnimator;
+
+  private DragHelper mDragHelper;
+
+  /**
+   * exclude cell when dragging(attributes for cell)
+   */
+  private static final String EXCLUDED = "dragExcluded";
+
+  /**
+   * the type to trigger drag-drop
+   */
+  private static final String DRAG_TRIGGER_TYPE = "dragTriggerType";
+
+  private static final String DEFAULT_TRIGGER_TYPE = DragTriggerType.LONG_PRESS;
+  private static final boolean DEFAULT_EXCLUDED = false;
+
+  private static final String DRAG_ANCHOR = "dragAnchor";
+
+  /**
+   * gesture type which can trigger drag&drop
+   */
+  interface DragTriggerType {
+    String PAN = "pan";
+    String LONG_PRESS = "longpress";
+  }
+
+  private String mTriggerType;
+
+  /**
+   * Map for storing component that is sticky.
+   **/
+  private Map<String, Map<String, WXComponent>> mStickyMap = new HashMap<>();
+  private WXStickyHelper stickyHelper;
+
+  /**
+   * scroll start and scroll end event
+   * */
+  private ScrollStartEndHelper mScrollStartEndHelper;
+
+  /**
+   * keep positon
+   * */
+  private  WXComponent keepPositionCell = null;
+  private  Runnable keepPositionCellRunnable = null;
+  private  long keepPositionLayoutDelay = 150;
+
+
+  public BasicListComponent(
+      WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+    stickyHelper = new WXStickyHelper(this);
+  }
+
+  @SuppressLint("RtlHardcoded")
+  @Override
+  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
+    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+      lp.setMargins(left, top, right, bottom);
+      lp.setMarginStart(left);
+      lp.setMarginEnd(right);
+    } else {
+      if (lp instanceof FrameLayout.LayoutParams) {
+        FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
+        if (this.isLayoutRTL()) {
+          lp_frameLayout.gravity = Gravity.RIGHT | Gravity.TOP;
+          lp.setMargins(right, top, left, bottom);
+        } else {
+          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
+          lp.setMargins(left, top, right, bottom);
+        }
+      } else {
+        lp.setMargins(left, top, right, bottom);
+      }
+    }
+  }
+
+  @Override
+  public void setLayout(WXComponent component) {
+    if (component.getHostView() != null) {
+      int layoutDirection = component.isLayoutRTL() ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
+      ViewCompat.setLayoutDirection(component.getHostView(), layoutDirection);
+    }
+    super.setLayout(component);
+  }
+
+  @Override
+  protected void onHostViewInitialized(T host) {
+    super.onHostViewInitialized(host);
+
+    WXRecyclerView recyclerView = host.getInnerView();
+    if (recyclerView == null || recyclerView.getAdapter() == null) {
+      WXLogUtils.e(TAG, "RecyclerView is not found or Adapter is not bound");
+      return;
+    }
+    if(WXUtils.getBoolean(getAttrs().get("prefetchGapDisable"), false)){
+      if(recyclerView.getLayoutManager() != null){
+        recyclerView.getLayoutManager().setItemPrefetchEnabled(false);
+      }
+    }
+
+    if (mChildren == null) {
+      WXLogUtils.e(TAG, "children is null");
+      return;
+    }
+
+    mDragHelper = new DefaultDragHelper(mChildren, recyclerView, new EventTrigger() {
+      @Override
+      public void triggerEvent(String type, Map<String, Object> args) {
+        fireEvent(type, args);
+      }
+    });
+
+    mTriggerType = getTriggerType(this);
+  }
+
+  /**
+   * Measure the size of the recyclerView.
+   *
+   * @param width  the expected width
+   * @param height the expected height
+   * @return the result of measurement
+   */
+  @Override
+  protected MeasureOutput measure(int width, int height) {
+    int screenH = WXViewUtils.getScreenHeight(getInstanceId());
+    int weexH = WXViewUtils.getWeexHeight(getInstanceId());
+    int outHeight = height > (weexH >= screenH ? screenH : weexH) ? weexH - getAbsoluteY() : height;
+    return super.measure(width, outHeight);
+  }
+
+  public int getOrientation() {
+    return Constants.Orientation.VERTICAL;
+  }
+
+  @Override
+  public void destroy() {
+    if(mAppearChangeRunnable != null &&  getHostView() != null) {
+      getHostView().removeCallbacks(mAppearChangeRunnable);
+      mAppearChangeRunnable = null;
+    }
+    super.destroy();
+    if (mStickyMap != null)
+      mStickyMap.clear();
+    if (mViewTypes != null)
+      mViewTypes.clear();
+    if (mRefToViewType != null)
+      mRefToViewType.clear();
+
+  }
+
+  @Override
+  public ViewGroup.LayoutParams getChildLayoutParams(WXComponent child, View hostView, int width, int height, int left, int right, int top, int bottom) {
+    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) hostView.getLayoutParams();
+    if (child instanceof WXBaseRefresh && params == null) {
+      params = new LinearLayout.LayoutParams(width, height);
+    } else if (params == null) {
+      params = new RecyclerView.LayoutParams(width, height);
+    } else {
+      params.width = width;
+      params.height = height;
+
+      this.setMarginsSupportRTL(params, left, 0, right, 0);
+    }
+    return params;
+  }
+
+  abstract T generateListView(Context context, int orientation);
+
+  @Override
+  protected T initComponentHostView(@NonNull Context context) {
+    T bounceRecyclerView = generateListView(context, getOrientation());
+
+    String transforms = getAttrByKey(TRANSFORM);
+    if (transforms != null) {
+      bounceRecyclerView.getInnerView().addItemDecoration(RecyclerTransform.parseTransforms(getOrientation(), transforms));
+    }
+    if(getAttrs().get(Constants.Name.KEEP_POSITION_LAYOUT_DELAY) != null){
+      keepPositionLayoutDelay = WXUtils.getNumberInt(getAttrs().get(Constants.Name.KEEP_POSITION_LAYOUT_DELAY), (int)keepPositionLayoutDelay);
+    }
+    if(getAttrs().get("appearActionDelay") != null){
+      mAppearChangeRunnableDelay =  WXUtils.getNumberInt(getAttrs().get("appearActionDelay"), (int) mAppearChangeRunnableDelay);
+    }
+
+    mItemAnimator=bounceRecyclerView.getInnerView().getItemAnimator();
+
+    RecyclerViewBaseAdapter recyclerViewBaseAdapter = new RecyclerViewBaseAdapter<>(this);
+    recyclerViewBaseAdapter.setHasStableIds(true);
+    bounceRecyclerView.setRecyclerViewBaseAdapter(recyclerViewBaseAdapter);
+    bounceRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
+    bounceRecyclerView.getInnerView().addOnScrollListener(mViewOnScrollListener);
+    if(getAttrs().get(Constants.Name.HAS_FIXED_SIZE) != null){
+      boolean hasFixedSize = WXUtils.getBoolean(getAttrs().get(Constants.Name.HAS_FIXED_SIZE), false);
+      bounceRecyclerView.getInnerView().setHasFixedSize(hasFixedSize);
+    }
+
+    bounceRecyclerView.getInnerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
+      @Override
+      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+        super.onScrollStateChanged(recyclerView, newState);
+        getScrollStartEndHelper().onScrollStateChanged(newState);
+        List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
+        int size;
+        OnWXScrollListener listener;
+        if (listeners != null && (size = listeners.size()) > 0) {
+          for (int i=0; i<size; ++i) {
+            if(i >= listeners.size()){
+              break;
+            }
+            listener = listeners.get(i);
+            if (listener != null) {
+              View topView = recyclerView.getChildAt(0);
+              if (topView != null) {
+                int y = topView.getTop();
+                listener.onScrollStateChanged(recyclerView, 0, y, newState);
+              }
+            }
+          }
+        }
+      }
+
+      @Override
+      public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+        super.onScrolled(recyclerView, dx, dy);
+        List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
+        if (listeners != null && listeners.size() > 0) {
+          try {
+            for (OnWXScrollListener listener : listeners) {
+              if (listener != null) {
+                if (listener instanceof ICheckBindingScroller) {
+                  if (((ICheckBindingScroller) listener).isNeedScroller(getRef(), null)) {
+                    listener.onScrolled(recyclerView, dx, dy);
+                  }
+                } else {
+                  listener.onScrolled(recyclerView, dx, dy);
+                }
+              }
+            }
+          } catch (Exception e) {
+            e.printStackTrace();
+          }
+        }
+      }
+    });
+
+    bounceRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+      @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+      @Override
+      public void onGlobalLayout() {
+        T view;
+        if ((view = getHostView()) == null)
+          return;
+        mViewOnScrollListener.onScrolled(view.getInnerView(), 0, 0);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+          view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+        } else {
+          view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+        }
+      }
+    });
+    return bounceRecyclerView;
+  }
+
+  @Override
+  public void bindStickStyle(WXComponent component) {
+    stickyHelper.bindStickStyle(component, mStickyMap);
+  }
+
+  @Override
+  public void unbindStickStyle(WXComponent component) {
+    stickyHelper.unbindStickStyle(component, mStickyMap);
+    WXHeader cell = (WXHeader) findTypeParent(component, WXHeader.class);
+    if(cell != null && getHostView() != null) {
+      getHostView().notifyStickyRemove(cell);
+    }
+  }
+
+  private
+  @Nullable
+  WXComponent findDirectListChild(WXComponent comp) {
+    WXComponent parent;
+    if (comp == null || (parent = comp.getParent()) == null) {
+      return null;
+    }
+
+    if (parent instanceof BasicListComponent) {
+      return comp;
+    }
+
+    return findDirectListChild(parent);
+  }
+
+  @Override
+  protected boolean setProperty(String key, Object param) {
+    switch (key) {
+      case LOADMOREOFFSET:
+        return true;
+      case Constants.Name.SCROLLABLE:
+        boolean scrollable = WXUtils.getBoolean(param, true);
+        setScrollable(scrollable);
+        return true;
+      case Constants.Name.OFFSET_ACCURACY:
+        int accuracy = WXUtils.getInteger(param, 10);
+        setOffsetAccuracy(accuracy);
+        return true;
+      case Constants.Name.DRAGGABLE:
+        boolean draggable = WXUtils.getBoolean(param,false);
+        setDraggable(draggable);
+        return true;
+      case Constants.Name.SHOW_SCROLLBAR:
+        Boolean result = WXUtils.getBoolean(param,null);
+        if (result != null)
+          setShowScrollbar(result);
+        return true;
+    }
+    return super.setProperty(key, param);
+  }
+
+  @WXComponentProp(name = Constants.Name.SCROLLABLE)
+  public void setScrollable(boolean scrollable) {
+    this.isScrollable = scrollable;
+    WXRecyclerView inner = getHostView().getInnerView();
+    if(inner != null) {
+      inner.setScrollable(scrollable);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.OFFSET_ACCURACY)
+  public void setOffsetAccuracy(int accuracy) {
+    float real = WXViewUtils.getRealPxByWidth(accuracy, getInstance().getInstanceViewPortWidth());
+    this.mOffsetAccuracy = (int) real;
+  }
+
+  @WXComponentProp(name = Constants.Name.DRAGGABLE)
+  public void setDraggable(boolean isDraggable) {
+    if (mDragHelper != null) {
+      mDragHelper.setDraggable(isDraggable);
+    }
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("set draggable : " + isDraggable);
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SHOW_SCROLLBAR)
+  public void setShowScrollbar(boolean show) {
+    if(getHostView() == null || getHostView().getInnerView() == null){
+      return;
+    }
+    if (getOrientation() == Constants.Orientation.VERTICAL) {
+      getHostView().getInnerView().setVerticalScrollBarEnabled(show);
+    } else {
+      getHostView().getInnerView().setHorizontalScrollBarEnabled(show);
+    }
+  }
+
+  @Override
+  public boolean isScrollable() {
+    return isScrollable;
+  }
+
+
+  private void setAppearanceWatch(WXComponent component, int event, boolean enable) {
+    AppearanceHelper item = mAppearComponents.get(component.getRef());
+    if (item != null) {
+      item.setWatchEvent(event, enable);
+    } else if (!enable) {
+      //Do nothing if disable target not exist.
+    } else {
+      WXComponent dChild = findDirectListChild(component);
+      int index = mChildren.indexOf(dChild);
+      if (index != -1) {
+        item = new AppearanceHelper(component, index);
+        item.setWatchEvent(event, true);
+        mAppearComponents.put(component.getRef(), item);
+      }
+    }
+  }
+
+  @Override
+  public void bindAppearEvent(WXComponent component) {
+    setAppearanceWatch(component, AppearanceHelper.APPEAR, true);
+    if(mAppearChangeRunnable == null){
+      mAppearChangeRunnable =  new Runnable() {
+        @Override
+        public void run() {
+          if(mAppearChangeRunnable != null) {
+            notifyAppearStateChange(0, 0, 0, 0);
+          }
+        }
+      };
+    }
+    if (getHostView() != null) {
+      getHostView().removeCallbacks(mAppearChangeRunnable);
+      getHostView().postDelayed(mAppearChangeRunnable, mAppearChangeRunnableDelay);
+    }
+  }
+
+  @Override
+  public void bindDisappearEvent(WXComponent component) {
+    setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, true);
+  }
+
+  @Override
+  public void unbindAppearEvent(WXComponent component) {
+    setAppearanceWatch(component, AppearanceHelper.APPEAR, false);
+  }
+
+  @Override
+  public void unbindDisappearEvent(WXComponent component) {
+    setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, false);
+  }
+
+  @Override
+  public void scrollTo(WXComponent component, Map<String, Object> options) {
+    float offsetFloat = 0;
+    boolean smooth = true;
+
+    if (options != null) {
+      String offsetStr = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
+      smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
+      if (offsetStr != null) {
+        try {
+          offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offsetStr), getInstance().getInstanceViewPortWidth());
+        }catch (Exception e ){
+          WXLogUtils.e("Float parseFloat error :"+e.getMessage());
+        }
+      }
+    }
+
+    final int offset = (int) offsetFloat;
+
+    T bounceRecyclerView = getHostView();
+    if (bounceRecyclerView == null) {
+      return;
+    }
+
+    WXComponent parent = component;
+    WXCell cell = null;
+    while (parent != null) {
+      if (parent instanceof WXCell) {
+        cell = (WXCell) parent;
+        break;
+      }
+      parent = parent.getParent();
+    }
+
+    if (cell != null) {
+      final int pos = mChildren.indexOf(cell);
+      if (pos == -1) {
+        //Invalid position
+        return;
+      }
+      final WXRecyclerView view = bounceRecyclerView.getInnerView();
+      view.scrollTo(smooth, pos, offset, getOrientation());
+    }
+  }
+
+  @Override
+  public void onBeforeScroll(int dx, int dy) {
+    T bounceRecyclerView = getHostView();
+    if (mStickyMap == null || bounceRecyclerView == null) {
+      return;
+    }
+    Map<String, WXComponent> stickyMap = mStickyMap.get(getRef());
+    if (stickyMap == null) {
+      return;
+    }
+    Iterator<Map.Entry<String, WXComponent>> iterator = stickyMap.entrySet().iterator();
+    Map.Entry<String, WXComponent> entry;
+    WXComponent stickyComponent;
+    int currentStickyPos = -1;
+    while (iterator.hasNext()) {
+      entry = iterator.next();
+      stickyComponent = entry.getValue();
+
+      if (stickyComponent != null && stickyComponent instanceof WXCell) {
+
+        WXCell cell = (WXCell) stickyComponent;
+        if (cell.getHostView() == null) {
+          return;
+        }
+
+        int[] location = new int[2];
+        stickyComponent.getHostView().getLocationOnScreen(location);
+        int[] parentLocation = new int[2];
+        stickyComponent.getParentScroller().getView().getLocationOnScreen(parentLocation);
+        int top = location[1] - parentLocation[1];
+
+
+        RecyclerView.LayoutManager layoutManager;
+        boolean beforeFirstVisibleItem = false;
+        boolean removeOldSticky = false;
+        layoutManager = getHostView().getInnerView().getLayoutManager();
+        if (layoutManager instanceof LinearLayoutManager || layoutManager instanceof GridLayoutManager) {
+          int firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+          int lastVisiblePosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
+          int pos = mChildren.indexOf(cell);
+          cell.setScrollPositon(pos);
+          if (pos <= firstVisiblePosition
+                  || (cell.getStickyOffset() > 0 && firstVisiblePosition < pos && pos <= lastVisiblePosition  &&
+                  top <= cell.getStickyOffset())) {
+            beforeFirstVisibleItem = true;
+            if(pos > currentStickyPos) {
+              currentStickyPos = pos;
+            }
+          }else{
+            removeOldSticky = true;
+          }
+        } else if(layoutManager instanceof StaggeredGridLayoutManager){
+          int [] firstItems= new int[3];
+          int firstVisiblePosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(firstItems)[0];
+          int lastVisiblePosition = ((StaggeredGridLayoutManager)  layoutManager).findLastVisibleItemPositions(firstItems)[0];
+          int pos = mChildren.indexOf(cell);
+
+          if (pos <= firstVisiblePosition || (cell.getStickyOffset() > 0 && firstVisiblePosition < pos && pos <= lastVisiblePosition  &&
+                  top <= cell.getStickyOffset())) {
+            beforeFirstVisibleItem = true;
+            if(pos > currentStickyPos) {
+              currentStickyPos = pos;
+            }
+          }else{
+            removeOldSticky = true;
+          }
+        }
+
+
+        boolean showSticky = beforeFirstVisibleItem && cell.getLocationFromStart() >= 0 && top <= cell.getStickyOffset() && dy >= 0;
+        boolean removeSticky = cell.getLocationFromStart() <= cell.getStickyOffset() && top > cell.getStickyOffset() && dy <= 0;
+        if (showSticky) {
+          bounceRecyclerView.notifyStickyShow(cell);
+        } else if (removeSticky || removeOldSticky) {
+          bounceRecyclerView.notifyStickyRemove(cell);
+        }
+        cell.setLocationFromStart(top);
+      }
+    }
+
+    if(currentStickyPos >= 0){
+      bounceRecyclerView.updateStickyView(currentStickyPos);
+    }else{
+      if(bounceRecyclerView instanceof BounceRecyclerView){
+        ((BounceRecyclerView) bounceRecyclerView).getStickyHeaderHelper().clearStickyHeaders();
+      }
+    }
+  }
+
+  @Override
+  public int getScrollY() {
+    T bounceRecyclerView = getHostView();
+    return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollY();
+  }
+
+  @Override
+  public int getScrollX() {
+    T bounceRecyclerView = getHostView();
+    return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollX();
+  }
+
+  /**
+   * Append a child component to the end of list. This will not refresh the underlying
+   * view immediately. The message of index of the inserted child is given to the adapter, and the
+   * adapter will determine when to refresh. The default implementation of adapter will push the
+   * message into a message and refresh the view in a period of time.
+   *
+   * @param child the inserted child
+   */
+  @Override
+  public void addChild(WXComponent child) {
+    addChild(child, -1);
+  }
+
+  @Override
+  protected int getChildrenLayoutTopOffset() {
+    return 0;
+  }
+
+  /**
+   * @param child the inserted child
+   * @param index the index of the child to be inserted.
+   * @see #addChild(WXComponent)
+   */
+  @Override
+  public void addChild(WXComponent child, int index) {
+    super.addChild(child, index);
+    if (child == null || index < -1) {
+      return;
+    }
+    int count = mChildren.size();
+    index = index >= count ? -1 : index;
+    bindViewType(child);
+
+    int adapterPosition = index == -1 ? mChildren.size() - 1 : index;
+    final T view = getHostView();
+    if (view != null) {
+      boolean isAddAnimation = false;
+      if (getBasicComponentData() != null) {
+        Object attr = getAttrs().get(Constants.Name.INSERT_CELL_ANIMATION);
+        if (Constants.Value.DEFAULT.equals(attr)) {
+          isAddAnimation = true;
+        }
+      }
+      if (isAddAnimation) {
+        view.getInnerView().setItemAnimator(mItemAnimator);
+      } else {
+        view.getInnerView().setItemAnimator(null);
+      }
+      boolean isKeepScrollPosition =  false;
+      if (child.getBasicComponentData() != null) {
+        Object attr = child.getAttrs().get(Constants.Name.KEEP_SCROLL_POSITION);
+        if (WXUtils.getBoolean(attr, false) && index <= getChildCount() && index>-1) {
+          isKeepScrollPosition = true;
+        }
+      }
+      if (isKeepScrollPosition) {
+        if(view.getInnerView().getLayoutManager() instanceof  LinearLayoutManager){
+          if(keepPositionCell == null){
+            int last=((LinearLayoutManager)view.getInnerView().getLayoutManager()).findLastCompletelyVisibleItemPosition();
+            ListBaseViewHolder holder = (ListBaseViewHolder) view.getInnerView().findViewHolderForAdapterPosition(last);
+            if(holder != null){
+              keepPositionCell = holder.getComponent();
+            }
+            if(keepPositionCell != null) {
+              if(!view.getInnerView().isLayoutFrozen()){ //frozen, prevent layout when scroll
+                view.getInnerView().setLayoutFrozen(true);
+              }
+              if(keepPositionCellRunnable != null){
+                view.removeCallbacks(keepPositionCellRunnable);
+              }
+              keepPositionCellRunnable = new Runnable() {
+                @Override
+                public void run() {
+                  if(keepPositionCell != null){
+                    int keepPosition = indexOf(keepPositionCell);
+                    int offset = 0;
+                    if(keepPositionCell.getHostView() != null){
+                      offset = keepPositionCell.getHostView().getTop();
+                    }
+                    if(offset > 0) {
+                      ((LinearLayoutManager) view.getInnerView().getLayoutManager()).scrollToPositionWithOffset(keepPosition, offset);
+                    }else{
+                      view.getInnerView().getLayoutManager().scrollToPosition(keepPosition);
+
+                    }
+                    view.getInnerView().setLayoutFrozen(false);
+                    keepPositionCell = null;
+                    keepPositionCellRunnable = null;
+                  }
+                }
+              };
+            }
+          }
+          if(keepPositionCellRunnable == null){
+            view.getInnerView().scrollToPosition(((LinearLayoutManager)view.getInnerView().getLayoutManager()).findLastVisibleItemPosition());
+          }
+        }
+        view.getRecyclerViewBaseAdapter().notifyItemInserted(adapterPosition);
+        if(keepPositionCellRunnable != null){
+          view.removeCallbacks(keepPositionCellRunnable);
+          view.postDelayed(keepPositionCellRunnable, keepPositionLayoutDelay);
+        }
+      } else {
+        view.getRecyclerViewBaseAdapter().notifyItemChanged(adapterPosition);
+      }
+    }
+    relocateAppearanceHelper();
+  }
+
+  private void relocateAppearanceHelper() {
+    Iterator<Map.Entry<String, AppearanceHelper>> iterator = mAppearComponents.entrySet().iterator();
+    while (iterator.hasNext()) {
+      Map.Entry<String, AppearanceHelper> item = iterator.next();
+      AppearanceHelper value = item.getValue();
+      WXComponent dChild = findDirectListChild(value.getAwareChild());
+      int index = mChildren.indexOf(dChild);
+      value.setCellPosition(index);
+    }
+  }
+
+
+  /**
+   * RecyclerView manage its children in a way that different from {@link WXVContainer}. Therefore,
+   * {@link WXVContainer#addSubView(View, int)} is an empty implementation in {@link
+   * WXRecyclerView}
+   */
+  @Override
+  public void addSubView(View child, int index) {
+
+  }
+
+  /**
+   * Remove the child from list. This method will use {@link
+   * java.util.List#indexOf(Object)} to retrieve the component to be deleted. Like {@link
+   * #addChild(WXComponent)}, this method will not refresh the view immediately, the adapter will
+   * decide when to refresh.
+   *
+   * @param child the child to be removed
+   */
+  @Override
+  public void remove(WXComponent child, boolean destroy) {
+    int index = mChildren.indexOf(child);
+    if (destroy) {
+      child.detachViewAndClearPreInfo();
+    }
+    unBindViewType(child);
+
+    T view = getHostView();
+    if (view == null) {
+      return;
+    }
+
+    boolean isRemoveAnimation = false;
+    Object attr = child.getAttrs().get(Constants.Name.DELETE_CELL_ANIMATION);
+    if (Constants.Value.DEFAULT.equals(attr)) {
+      isRemoveAnimation = true;
+    }
+    if (isRemoveAnimation) {
+      view.getInnerView().setItemAnimator(mItemAnimator);
+    } else {
+      view.getInnerView().setItemAnimator(null);
+    }
+
+    view.getRecyclerViewBaseAdapter().notifyItemRemoved(index);
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d(TAG, "removeChild child at " + index);
+    }
+    super.remove(child, destroy);
+  }
+
+
+
+  @Override
+  public void computeVisiblePointInViewCoordinate(PointF pointF) {
+    RecyclerView view = getHostView().getInnerView();
+    pointF.set(view.computeHorizontalScrollOffset(), view.computeVerticalScrollOffset());
+  }
+
+  /**
+   * Recycle viewHolder and its underlying view. This may because the view is removed or reused.
+   * Either case, this method will be called.
+   *
+   * @param holder The view holder to be recycled.
+   */
+  @Override
+  public void onViewRecycled(ListBaseViewHolder holder) {
+    long begin = System.currentTimeMillis();
+
+    holder.setComponentUsing(false);
+    if (holder != null
+            && holder.canRecycled()
+            && holder.getComponent() != null
+            && !holder.getComponent().isUsing()) {
+      holder.recycled();
+
+    } else {
+      WXLogUtils.w(TAG, "this holder can not be allowed to  recycled");
+    }
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d(TAG, "Recycle holder " + (System.currentTimeMillis() - begin) + "  Thread:" + Thread.currentThread().getName());
+    }
+  }
+
+  /**
+   * Bind the component of the position to the holder. Then flush the view.
+   *
+   * @param holder   viewHolder, which holds reference to the view
+   * @param position position of component in list
+   */
+  @Override
+  public void onBindViewHolder(final ListBaseViewHolder holder, int position) {
+    if (holder == null) return;
+    holder.setComponentUsing(true);
+    WXComponent component = getChild(position);
+    if (component == null
+            || (component instanceof WXRefresh)
+            || (component instanceof WXLoading)
+            || (component.isFixed())
+            ) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d(TAG, "Bind WXRefresh & WXLoading " + holder);
+      }
+      if(component instanceof  WXBaseRefresh
+              && holder.getView() != null
+              && (component.getAttrs().get("holderBackground") != null)){
+        Object holderBackground = component.getAttrs().get("holderBackground");
+        int color = WXResourceUtils.getColor(holderBackground.toString(), Color.WHITE);
+        holder.getView().setBackgroundColor(color);
+        holder.getView().setVisibility(View.VISIBLE);
+        holder.getView().postInvalidate();
+      }
+      return;
+    }
+
+    if (holder.getComponent() != null && holder.getComponent() instanceof WXCell) {
+      if(holder.isRecycled()) {
+        holder.bindData(component);
+        component.onRenderFinish(STATE_UI_FINISH);
+      }
+      if (mDragHelper == null || !mDragHelper.isDraggable()) {
+        return;
+      }
+      mTriggerType = (mTriggerType == null) ? DEFAULT_TRIGGER_TYPE : mTriggerType;
+
+      WXCell cell = (WXCell) holder.getComponent();
+      boolean isExcluded = DEFAULT_EXCLUDED;
+      WXAttr cellAttrs = cell.getAttrs();
+      isExcluded = WXUtils.getBoolean(cellAttrs.get(EXCLUDED), DEFAULT_EXCLUDED);
+
+      mDragHelper.setDragExcluded(holder, isExcluded);
+
+      //NOTICE: event maybe consumed by other views
+      if (DragTriggerType.PAN.equals(mTriggerType)) {
+        mDragHelper.setLongPressDragEnabled(false);
+
+        WXComponent anchorComponent = findComponentByAnchorName(cell, DRAG_ANCHOR);
+
+        if (anchorComponent != null && anchorComponent.getHostView() != null && !isExcluded) {
+          View anchor = anchorComponent.getHostView();
+          anchor.setOnTouchListener(new View.OnTouchListener() {
+            @SuppressLint("ClickableViewAccessibility")
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+              if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+                mDragHelper.startDrag(holder);
+              }
+              return true;
+            }
+          });
+        } else {
+          if (WXEnvironment.isApkDebugable()) {
+            if(!isExcluded) {
+              WXLogUtils.e(TAG, "[error] onBindViewHolder: the anchor component or view is not found");
+            } else {
+              WXLogUtils.d(TAG, "onBindViewHolder: position "+ position + " is drag excluded");
+            }
+          }
+        }
+
+      } else if (DragTriggerType.LONG_PRESS.equals(mTriggerType)) {
+        mDragHelper.setLongPressDragEnabled(true);
+      }
+    }
+
+  }
+
+  protected void markComponentUsable(){
+    for (WXComponent component : mChildren){
+      component.setUsing(false);
+    }
+  }
+  /**
+   * Create an instance of {@link ListBaseViewHolder} for the given viewType (not for the given
+   * index). This  markComponentUsable();method will look up for the first component that fits the viewType requirement and
+   * doesn't be used. Then create the certain type of view, detach the view f[rom the component.
+   *
+   * @param parent   the ViewGroup into which the new view will be inserted
+   * @param viewType the type of the new view
+   * @return the created view holder.
+   */
+  @Override
+  public ListBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+    if (mChildren != null) {
+      if (mViewTypes == null)
+        return createVHForFakeComponent(viewType);
+      ArrayList<WXComponent> mTypes = mViewTypes.get(viewType);
+      checkRecycledViewPool(viewType);
+      if (mTypes == null)
+        return createVHForFakeComponent(viewType);
+
+      for (int i = 0; i < mTypes.size(); i++) {
+        WXComponent component = mTypes.get(i);
+        if (component == null
+            || component.isUsing()) {
+          continue;
+        }
+        if (component.isFixed()) {
+          return createVHForFakeComponent(viewType);
+        } else {
+          if (component instanceof WXCell) {
+            if (component.getRealView() != null) {
+              return new ListBaseViewHolder(component, viewType);
+            } else {
+              component.lazy(false);
+              component.createView();
+              component.applyLayoutAndEvent(component);
+              return new ListBaseViewHolder(component, viewType, true);
+            }
+          } else if (component instanceof WXBaseRefresh) {
+            return createVHForRefreshComponent(viewType);
+          } else {
+            WXLogUtils.e(TAG, "List cannot include element except cell、header、fixed、refresh and loading");
+            return createVHForFakeComponent(viewType);
+          }
+        }
+      }
+    }
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.e(TAG, "Cannot find request viewType: " + viewType);
+    }
+    return createVHForFakeComponent(viewType);
+  }
+
+  /**
+   * Forbid ViewHolder cache if viewType > MAX_VIEWTYPE_ALLOW_CACHE
+   *
+   * @param viewType
+   */
+  private void checkRecycledViewPool(int viewType) {
+    try {
+      if (mViewTypes.size() > MAX_VIEWTYPE_ALLOW_CACHE)
+        mAllowCacheViewHolder = false;
+
+      if (mDownForBidCacheViewHolder)
+        if (getHostView() != null && getHostView().getInnerView() != null)
+          getHostView().getInnerView().getRecycledViewPool().setMaxRecycledViews(viewType, 0);
+
+      if (!mDownForBidCacheViewHolder) {
+        if (!mAllowCacheViewHolder) {
+          if (getHostView() != null && getHostView().getInnerView() != null) {
+            for (int i = 0; i < mViewTypes.size(); i++) {
+              getHostView().getInnerView().getRecycledViewPool().setMaxRecycledViews(mViewTypes.keyAt(i), 0);
+            }
+            mDownForBidCacheViewHolder = true;
+          }
+        }
+      }
+    } catch (Exception e) {
+      WXLogUtils.e(TAG, "Clear recycledViewPool error!");
+    }
+  }
+
+  /**
+   * Return the child component type. The type is defined by scopeValue in .we file.
+   *
+   * @param position the position of the child component.
+   * @return the type of certain component.
+   */
+  @Override
+  public int getItemViewType(int position) {
+    return generateViewType(getChild(position));
+  }
+
+  @Nullable
+  private WXComponent findComponentByAnchorName(@NonNull WXComponent root, @NonNull String anchorName) {
+    long start = 0;
+    if (WXEnvironment.isApkDebugable()) {
+      start = System.currentTimeMillis();
+    }
+
+    Deque<WXComponent> deque = new ArrayDeque<>();
+    deque.add(root);
+    while (!deque.isEmpty()) {
+      WXComponent curComponent = deque.removeFirst();
+      if (curComponent != null) {
+        String isAnchorSet = WXUtils.getString(curComponent.getAttrs().get(anchorName), null);
+
+        //hit
+        if (isAnchorSet != null && isAnchorSet.equals("true")) {
+          if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d("dragPerf", "findComponentByAnchorName time: " + (System.currentTimeMillis() - start) + "ms");
+          }
+          return curComponent;
+        }
+      }
+      if (curComponent instanceof WXVContainer) {
+        WXVContainer container = (WXVContainer) curComponent;
+        for (int i = 0, len = container.childCount(); i < len; i++) {
+          WXComponent child = container.getChild(i);
+          deque.add(child);
+        }
+      }
+    }
+
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("dragPerf", "findComponentByAnchorName elapsed time: " + (System.currentTimeMillis() - start) + "ms");
+    }
+    return null;
+
+  }
+
+  private String getTriggerType(@Nullable WXComponent component) {
+    String triggerType = DEFAULT_TRIGGER_TYPE;
+    if (component == null) {
+      return triggerType;
+    }
+    triggerType = WXUtils.getString(component.getAttrs().get(DRAG_TRIGGER_TYPE), DEFAULT_TRIGGER_TYPE);
+    if (!DragTriggerType.LONG_PRESS.equals(triggerType) && !DragTriggerType.PAN.equals(triggerType)) {
+      triggerType = DEFAULT_TRIGGER_TYPE;
+    }
+
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d(TAG, "trigger type is " + triggerType);
+    }
+
+    return triggerType;
+  }
+
+
+  /**
+   * ViewType will be classified into {HashMap<Integer,ArrayList<Integer>> mViewTypes}
+   *
+   * @param component
+   */
+  private void bindViewType(WXComponent component) {
+    int id = generateViewType(component);
+
+    if (mViewTypes == null) {
+      mViewTypes = new SparseArray<>();
+    }
+
+    ArrayList<WXComponent> mTypes = mViewTypes.get(id);
+
+    if (mTypes == null) {
+      mTypes = new ArrayList<>();
+      mViewTypes.put(id, mTypes);
+    }
+    mTypes.add(component);
+  }
+
+  private void unBindViewType(WXComponent component) {
+    int id = generateViewType(component);
+
+    if (mViewTypes == null)
+      return;
+    ArrayList<WXComponent> mTypes = mViewTypes.get(id);
+    if (mTypes == null)
+      return;
+
+    mTypes.remove(component);
+  }
+
+  /**
+   * generate viewtype by component
+   *
+   * @param component
+   * @return
+   */
+  private int generateViewType(WXComponent component) {
+    long id;
+    try {
+      id = Integer.parseInt(component.getRef());
+      String type = component.getAttrs().getScope();
+
+      if (!TextUtils.isEmpty(type)) {
+        if (mRefToViewType == null) {
+          mRefToViewType = new ArrayMap<>();
+        }
+        if (!mRefToViewType.containsKey(type)) {
+          mRefToViewType.put(type, id);
+        }
+        id = mRefToViewType.get(type);
+
+      }
+    } catch (RuntimeException e) {
+      WXLogUtils.eTag(TAG, e);
+      id = RecyclerView.NO_ID;
+      WXLogUtils.e(TAG, "getItemViewType: NO ID, this will crash the whole render system of WXListRecyclerView");
+    }
+    return (int) id;
+  }
+
+  /**
+   * Get child component num.
+   *
+   * @return return the size of {@link #mChildren} if mChildren is not empty, otherwise, return 0;
+   */
+  @Override
+  public int getItemCount() {
+    return getChildCount();
+  }
+
+  @Override
+  public boolean onFailedToRecycleView(ListBaseViewHolder holder) {
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d(TAG, "Failed to recycle " + holder);
+    }
+    return false;
+  }
+
+  @Override
+  public long getItemId(int position) {
+    long id;
+    try {
+      id = Long.parseLong(getChild(position).getRef());
+    } catch (RuntimeException e) {
+      WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
+      id = RecyclerView.NO_ID;
+    }
+    return id;
+  }
+
+  @Override
+  public void onLoadMore(int offScreenY) {
+    try {
+      String offset = getAttrs().getLoadMoreOffset();
+
+      if (TextUtils.isEmpty(offset)) {
+        offset = "0";
+      }
+
+
+      float offsetParsed = WXViewUtils.getRealPxByWidth(WXUtils.getInt(offset),getInstance().getInstanceViewPortWidth());
+
+      if (offScreenY <= offsetParsed && getEvents().contains(Constants.Event.LOADMORE)) {
+        if (mListCellCount != mChildren.size()
+            || mForceLoadmoreNextTime) {
+          fireEvent(Constants.Event.LOADMORE);
+          mListCellCount = mChildren.size();
+          mForceLoadmoreNextTime = false;
+        }
+      }
+    } catch (Exception e) {
+      WXLogUtils.d(TAG + "onLoadMore :", e);
+    }
+  }
+
+  @Override
+  public void notifyAppearStateChange(int firstVisible, int lastVisible, int directionX, int directionY) {
+    if(mAppearChangeRunnable != null) {
+      getHostView().removeCallbacks(mAppearChangeRunnable);
+      mAppearChangeRunnable = null;
+    }
+    //notify appear state
+    Iterator<AppearanceHelper> it = mAppearComponents.values().iterator();
+    String direction = directionY > 0 ? Constants.Value.DIRECTION_UP :
+            directionY < 0 ? Constants.Value.DIRECTION_DOWN : null;
+    if (getOrientation() == Constants.Orientation.HORIZONTAL && directionX != 0) {
+      direction = directionX > 0 ? Constants.Value.DIRECTION_LEFT : Constants.Value.DIRECTION_RIGHT;
+    }
+
+    while (it.hasNext()) {
+      AppearanceHelper item = it.next();
+      WXComponent component = item.getAwareChild();
+
+      if (!item.isWatch()) {
+        continue;
+      }
+
+
+      View view = component.getHostView();
+      if (view == null) {
+        continue;
+      }
+
+      boolean outOfVisibleRange = !ViewCompat.isAttachedToWindow(view);
+      boolean visible = (!outOfVisibleRange) && item.isViewVisible(true);
+
+      int result = item.setAppearStatus(visible);
+      if (result == AppearanceHelper.RESULT_NO_CHANGE) {
+        continue;
+      }
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d("appear", "item " + item.getCellPositionINScollable() + " result " + result);
+      }
+      component.notifyAppearStateChange(result == AppearanceHelper.RESULT_APPEAR ? Constants.Event.APPEAR : Constants.Event.DISAPPEAR, direction);
+    }
+  }
+
+  @NonNull
+  private ListBaseViewHolder createVHForFakeComponent(int viewType) {
+    FrameLayout view = new FrameLayout(getContext());
+    view.setBackgroundColor(Color.WHITE);
+    view.setLayoutParams(new FrameLayout.LayoutParams(0, 0));
+    return new ListBaseViewHolder(view, viewType);
+  }
+
+
+  private ListBaseViewHolder createVHForRefreshComponent(int viewType) {
+    FrameLayout view = new FrameLayout(getContext());
+    view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
+    return new ListBaseViewHolder(view, viewType);
+  }
+
+  @JSMethod
+  public void resetLoadmore() {
+    mForceLoadmoreNextTime = true;
+    mListCellCount = 0;
+  }
+
+  @Override
+  public void addEvent(String type) {
+    super.addEvent(type);
+    if (ScrollStartEndHelper.isScrollEvent(type)
+            && getHostView() != null
+            && getHostView().getInnerView() != null
+            && !mHasAddScrollEvent) {
+      mHasAddScrollEvent = true;
+      WXRecyclerView innerView = getHostView().getInnerView();
+      innerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+        private int offsetXCorrection, offsetYCorrection;
+        private boolean mFirstEvent = true;
+
+        @Override
+        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+          super.onScrolled(recyclerView, dx, dy);
+//          WXLogUtils.e("SCROLL", dx + ", " + dy + ", " + recyclerView.computeHorizontalScrollRange()
+//          + ", " + recyclerView.computeVerticalScrollRange()
+//          + ", " + recyclerView.computeHorizontalScrollOffset()
+//          + ", " + recyclerView.computeVerticalScrollOffset());
+
+          int offsetX = recyclerView.computeHorizontalScrollOffset();
+          int offsetY = recyclerView.computeVerticalScrollOffset();
+
+          if (dx == 0 && dy == 0) {
+            offsetXCorrection = offsetX;
+            offsetYCorrection = offsetY;
+            offsetX = 0;
+            offsetY = 0;
+          } else {
+            offsetX = offsetX - offsetXCorrection;
+            offsetY = offsetY - offsetYCorrection;
+          }
+          getScrollStartEndHelper().onScrolled(offsetX, offsetY);
+          if(!getEvents().contains(Constants.Event.SCROLL)){
+            return;
+          }
+          if (mFirstEvent) {
+            //skip first event
+            mFirstEvent = false;
+            return;
+          }
+
+          RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+          if (!layoutManager.canScrollVertically()) {
+            return;
+          }
+
+          if (shouldReport(offsetX, offsetY)) {
+            fireScrollEvent(recyclerView, offsetX, offsetY);
+          }
+        }
+      });
+    }
+  }
+
+  private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY) {
+    fireEvent(Constants.Event.SCROLL, getScrollEvent(recyclerView, offsetX, offsetY));
+  }
+
+  public Map<String, Object> getScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY){
+    if(getOrientation() == Constants.Orientation.VERTICAL){
+      offsetY = - calcContentOffset(recyclerView);
+    }
+    int contentWidth = recyclerView.getMeasuredWidth() + recyclerView.computeHorizontalScrollRange();
+    int contentHeight = 0;
+    for (int i = 0; i < getChildCount(); i++) {
+      WXComponent child = getChild(i);
+      if (child != null) {
+        contentHeight += child.getLayoutHeight();
+      }
+    }
+
+    Map<String, Object> event = new HashMap<>(3);
+    Map<String, Object> contentSize = new HashMap<>(3);
+    Map<String, Object> contentOffset = new HashMap<>(3);
+
+    contentSize.put(Constants.Name.WIDTH, WXViewUtils.getWebPxByWidth(contentWidth, getInstance().getInstanceViewPortWidth()));
+    contentSize.put(Constants.Name.HEIGHT, WXViewUtils.getWebPxByWidth(contentHeight, getInstance().getInstanceViewPortWidth()));
+
+    contentOffset.put(Constants.Name.X, - WXViewUtils.getWebPxByWidth(offsetX, getInstance().getInstanceViewPortWidth()));
+    contentOffset.put(Constants.Name.Y, - WXViewUtils.getWebPxByWidth(offsetY, getInstance().getInstanceViewPortWidth()));
+    event.put(Constants.Name.CONTENT_SIZE, contentSize);
+    event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
+    event.put(Constants.Name.ISDRAGGING, recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING);
+    return event;
+  }
+
+  private boolean shouldReport(int offsetX, int offsetY) {
+    if (mLastReport.x == -1 && mLastReport.y == -1) {
+      mLastReport.x = offsetX;
+      mLastReport.y = offsetY;
+      return true;
+    }
+
+    int gapX = Math.abs(mLastReport.x - offsetX);
+    int gapY = Math.abs(mLastReport.y - offsetY);
+
+    if (gapX >= mOffsetAccuracy || gapY >= mOffsetAccuracy) {
+      mLastReport.x = offsetX;
+      mLastReport.y = offsetY;
+      return true;
+    }
+
+    return false;
+  }
+
+
+
+  public int calcContentOffset(RecyclerView recyclerView) {
+    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+    if (layoutManager instanceof LinearLayoutManager) {
+      int firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+      if (firstVisibleItemPosition == -1) {
+        return 0;
+      }
+
+      View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
+      int firstVisibleViewOffset = 0;
+      if (firstVisibleView != null) {
+        firstVisibleViewOffset = firstVisibleView.getTop();
+      }
+
+      int offset = 0;
+      for (int i=0;i<firstVisibleItemPosition;i++) {
+        WXComponent child = getChild(i);
+        if (child != null) {
+          offset -= child.getLayoutHeight();
+        }
+      }
+
+      if (layoutManager instanceof GridLayoutManager) {
+        int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
+        offset = offset / spanCount;
+      }
+
+      offset += firstVisibleViewOffset;
+      return offset;
+    } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+      int spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
+      int firstVisibleItemPosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(null)[0];
+      if (firstVisibleItemPosition == -1) {
+        return 0;
+      }
+
+      View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
+      int firstVisibleViewOffset = 0;
+      if (firstVisibleView != null) {
+        firstVisibleViewOffset = firstVisibleView.getTop();
+      }
+
+      int offset = 0;
+      for (int i=0;i<firstVisibleItemPosition;i++) {
+        WXComponent child = getChild(i);
+        if (child != null) {
+          offset -= child.getLayoutHeight();
+        }
+      }
+
+      offset = offset / spanCount;
+      offset += firstVisibleViewOffset;
+      return offset;
+    }
+    //Unhandled LayoutManager type
+    return -1;
+  }
+
+  public ScrollStartEndHelper getScrollStartEndHelper() {
+    if(mScrollStartEndHelper == null){
+      mScrollStartEndHelper = new ScrollStartEndHelper(this);
+    }
+    return mScrollStartEndHelper;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/DefaultDragHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/DefaultDragHelper.java
new file mode 100644
index 0000000..944e91c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/DefaultDragHelper.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Description:
+ * Drag-drop support for list
+ * <p>
+ * Created by rowandjj(chuyi)<br/>
+ */
+
+class DefaultDragHelper implements DragHelper {
+
+    private boolean mLongPressEnabled;
+
+    @NonNull
+    private final EventTrigger mEventTrigger;
+    @NonNull
+    private final RecyclerView mRecyclerView;
+    @NonNull
+    private final List<WXComponent> mDataSource;
+    @NonNull
+    private ItemTouchHelper mItemTouchHelper;
+
+    private static final String EVENT_START_DRAG = "dragstart";
+    private static final String EVENT_END_DRAG = "dragend";
+
+    private static final String TAG_EXCLUDED = "drag_excluded";
+
+    private static final String TAG = "WXListExComponent";
+
+    private boolean isDraggable = false;
+
+    DefaultDragHelper(@NonNull List<WXComponent> dataSource, @NonNull RecyclerView recyclerView, @NonNull EventTrigger trigger) {
+        this.mDataSource = dataSource;
+        this.mEventTrigger = trigger;
+        this.mRecyclerView = recyclerView;
+
+        //attach
+        this.mItemTouchHelper = new ItemTouchHelper(new DragSupportCallback(this, true));
+        try {
+            mItemTouchHelper.attachToRecyclerView(mRecyclerView);
+        }catch (Throwable e) {
+            //ignore
+        }
+    }
+
+    @Override
+    public void onDragStart(@NonNull WXComponent component, int from) {
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d(TAG, "list on drag start : from index " + from);
+        }
+        mEventTrigger.triggerEvent(EVENT_START_DRAG, buildEvent(component.getRef(), from, -1));
+    }
+
+    @Override
+    public void onDragEnd(@NonNull WXComponent component, int from, int to) {
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d(TAG, "list on drag end : " + "from index " + from + " to index " + to);
+        }
+        mEventTrigger.triggerEvent(EVENT_END_DRAG, buildEvent(component.getRef(), from, to));
+    }
+
+    @Override
+    public void onDragging(int fromPos, int toPos) {
+        if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d(TAG, "list on dragging : from index " + fromPos + " to index " + toPos);
+        }
+
+        RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
+        if (adapter == null) {
+            WXLogUtils.e(TAG, "drag failed because of RecyclerView#Adapter is not bound");
+            return;
+        }
+
+        if (fromPos >= 0 && fromPos <= mDataSource.size() - 1 && toPos >= 0 && toPos <= mDataSource.size() - 1) {
+            Collections.swap(mDataSource, fromPos, toPos);
+            adapter.notifyItemMoved(fromPos, toPos);
+        }
+    }
+
+    @Override
+    public boolean isLongPressDragEnabled() {
+        return mLongPressEnabled;
+    }
+
+    @Override
+    public void setLongPressDragEnabled(boolean enabled) {
+        this.mLongPressEnabled = enabled;
+    }
+
+    @Override
+    public void startDrag(@NonNull RecyclerView.ViewHolder viewHolder) {
+        if (isDraggable) {
+            mItemTouchHelper.startDrag(viewHolder);
+        }
+    }
+
+    @Override
+    public boolean isDraggable() {
+        return this.isDraggable;
+    }
+
+    @Override
+    public void setDraggable(boolean draggable) {
+        this.isDraggable = draggable;
+    }
+
+    @Override
+    public void setDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder, boolean isExcluded) {
+        if (viewHolder.itemView == null) {
+            if (WXEnvironment.isApkDebugable()) {
+                WXLogUtils.e(TAG, "[error] viewHolder.itemView is null");
+            }
+            return;
+        }
+        if (isExcluded) {
+            viewHolder.itemView.setTag(TAG_EXCLUDED);
+        } else {
+            viewHolder.itemView.setTag(null);
+        }
+    }
+
+    @Override
+    public boolean isDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder) {
+        if (viewHolder.itemView == null) {
+            if (WXEnvironment.isApkDebugable()) {
+                WXLogUtils.e(TAG, "[error] viewHolder.itemView is null");
+            }
+            return false;
+        }
+        return viewHolder.itemView.getTag() != null && TAG_EXCLUDED.equals(viewHolder.itemView.getTag());
+    }
+
+    private Map<String, Object> buildEvent(@Nullable String target, int fromIndex, int toIndex) {
+        Map<String, Object> args = new HashMap<>(4);
+        args.put("target", target == null ? "unknown" : target);
+        args.put("fromIndex", fromIndex);
+        args.put("toIndex", toIndex);
+        args.put("timestamp", System.currentTimeMillis());
+        return args;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/DragHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/DragHelper.java
new file mode 100644
index 0000000..8d3337f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/DragHelper.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Description:
+ *
+ * interface for drag&drop support
+ *
+ */
+interface DragHelper {
+
+    void onDragStart(@NonNull WXComponent component, int from);
+
+    void onDragEnd(@NonNull WXComponent component, int from, int to);
+
+    void onDragging(int fromPos, int toPos);
+
+    boolean isLongPressDragEnabled();
+
+    void setLongPressDragEnabled(boolean enabled);
+
+    void startDrag(@NonNull RecyclerView.ViewHolder viewHolder);
+
+    boolean isDraggable();
+
+    void setDraggable(boolean draggable);
+
+    void setDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder, boolean isExcluded);
+
+    boolean isDragExcluded(@NonNull RecyclerView.ViewHolder viewHolder);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/DragSupportCallback.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/DragSupportCallback.java
new file mode 100644
index 0000000..0a71b3b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/DragSupportCallback.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.support.annotation.NonNull;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+import org.apache.weex.ui.view.listview.adapter.ListBaseViewHolder;
+import org.apache.weex.utils.WXLogUtils;
+
+/**
+ * Description:
+ * An implementation of {@link ItemTouchHelper.Callback}. with drag&drop support:)
+ *
+ */
+class DragSupportCallback extends ItemTouchHelper.Callback {
+    private final DragHelper mDragHelper;
+    private boolean mEnableDifferentViewTypeDrag = false;
+
+    private int dragFrom = -1;
+    private int dragTo = -1;
+
+    private static final String TAG = "WXListExComponent";
+
+    DragSupportCallback(@NonNull DragHelper DragHelper) {
+        this.mDragHelper = DragHelper;
+        this.mEnableDifferentViewTypeDrag = false;
+    }
+
+    DragSupportCallback(@NonNull DragHelper DragHelper, boolean enableDifferentViewTypeDrag) {
+        this.mDragHelper = DragHelper;
+        this.mEnableDifferentViewTypeDrag = enableDifferentViewTypeDrag;
+    }
+
+    @Override
+    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+        if (recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
+            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
+            int swipeFlags = 0;
+            return makeMovementFlags(dragFlags, swipeFlags);
+        } else {
+            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+            int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
+            return makeMovementFlags(dragFlags, swipeFlags);
+        }
+    }
+
+    @Override
+    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
+        if (viewHolder == null || target == null) {
+            return false;
+        }
+
+        if (!mEnableDifferentViewTypeDrag && viewHolder.getItemViewType() != target.getItemViewType()) {
+            return false;
+        }
+
+        if (mDragHelper.isDragExcluded(viewHolder)) {
+            return false;
+        }
+
+        try {
+            int fromPos = viewHolder.getAdapterPosition();
+            int toPos = target.getAdapterPosition();
+
+            if (dragFrom == -1) {
+                dragFrom = fromPos;
+            }
+            dragTo = toPos;
+
+            mDragHelper.onDragging(fromPos, toPos);
+            return true;
+        } catch (Exception e) {
+            WXLogUtils.e(TAG, e.getMessage());
+            return false;
+        }
+    }
+
+
+    @Override
+    public boolean isLongPressDragEnabled() {
+        return mDragHelper.isDraggable() && mDragHelper.isLongPressDragEnabled();
+    }
+
+    @Override
+    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+    }
+
+    @Override
+    public boolean isItemViewSwipeEnabled() {
+        return false;
+    }
+
+    @Override
+    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && viewHolder instanceof ListBaseViewHolder) {
+            ListBaseViewHolder vh = (ListBaseViewHolder) viewHolder;
+            if (vh.getComponent() != null) {
+                mDragHelper.onDragStart(vh.getComponent(), vh.getAdapterPosition());
+            }
+        }
+
+        super.onSelectedChanged(viewHolder, actionState);
+    }
+
+
+    @Override
+    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+        super.clearView(recyclerView, viewHolder);
+
+        if (viewHolder instanceof ListBaseViewHolder) {
+            ListBaseViewHolder vh = (ListBaseViewHolder) viewHolder;
+            if (vh.getComponent() != null) {
+                if (dragFrom != -1 && dragTo != -1) {
+                    mDragHelper.onDragEnd(vh.getComponent(), dragFrom, dragTo);
+                }
+            }
+
+        }
+
+        dragFrom = dragTo = -1;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/EventTrigger.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/EventTrigger.java
new file mode 100644
index 0000000..9cf2c37
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/EventTrigger.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import java.util.Map;
+
+interface EventTrigger {
+    void triggerEvent(String type, Map<String, Object> args);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/GapItemDecoration.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/GapItemDecoration.java
new file mode 100644
index 0000000..0f58a25
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/GapItemDecoration.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.View;
+
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.utils.WXViewUtils;
+
+/**
+ * Created by furture on 2018/2/12.
+ * recyclerview's height is layout width + column gap,
+ * so the the offset should include, leftGap and rightGap is via this
+ */
+public class GapItemDecoration extends RecyclerView.ItemDecoration {
+
+    private WXListComponent listComponent;
+
+    public GapItemDecoration(WXListComponent listComponent) {
+        this.listComponent = listComponent;
+    }
+
+    @Override
+    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+        final Float[] spanOffsets = listComponent.getSpanOffsets();
+        if (spanOffsets == null) {
+            return;
+        }
+        int position = parent.getChildAdapterPosition(view);
+        if(position < 0) {
+            return;
+        }
+        if(view.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams){
+            StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
+            if(params.isFullSpan()){
+                return;
+            }
+            WXComponent component = listComponent.getChild(position);
+            if(component instanceof WXCell){
+                WXCell cell = (WXCell) component;
+                if(cell.isFixed() || cell.isSticky()) {
+                    return;
+                }
+
+                if (params.getSpanIndex() >= spanOffsets.length) {
+                    return;
+                }
+
+                int index = listComponent.isLayoutRTL() ? spanOffsets.length - params.getSpanIndex() - 1 : params.getSpanIndex();
+                float spanOffset = listComponent.getSpanOffsets()[index];
+                int   spanOffsetPx =  Math.round(WXViewUtils.getRealPxByWidth(spanOffset, listComponent.getViewPortWidth()));
+                if (listComponent.isLayoutRTL()) {
+                    outRect.left = -spanOffsetPx;
+                    outRect.right = spanOffsetPx;
+                } else {
+                    outRect.left = spanOffsetPx;
+                    outRect.right = -spanOffsetPx;
+                }
+            }
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/HorizontalListComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/HorizontalListComponent.java
new file mode 100644
index 0000000..1473b8d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/HorizontalListComponent.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXVContainer;
+
+/**
+ * Created by sospartan on 6/2/16.
+ */
+@Component(lazyload = false)
+
+public class HorizontalListComponent extends WXListComponent {
+  public HorizontalListComponent(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
+    super(instance, parent, lazy, basicComponentData);
+  }
+
+  @Override
+  public int getOrientation() {
+    return Constants.Orientation.HORIZONTAL;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/ListComponentView.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/ListComponentView.java
new file mode 100644
index 0000000..0b6fdd7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/ListComponentView.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+import org.apache.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
+
+/**
+ * Created by sospartan on 13/12/2016.
+ */
+
+public interface ListComponentView {
+  WXRecyclerView getInnerView();
+  void setRecyclerViewBaseAdapter(RecyclerViewBaseAdapter adapter);
+  void notifyStickyShow(WXCell component);
+  void notifyStickyRemove(WXCell component);
+  void updateStickyView(int currentStickyPos);
+  RecyclerViewBaseAdapter getRecyclerViewBaseAdapter();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/RecyclerTransform.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/RecyclerTransform.java
new file mode 100644
index 0000000..6117741
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/RecyclerTransform.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.support.v7.widget.RecyclerView;
+
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.view.listview.adapter.TransformItemDecoration;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * recycler item decoration transform
+ * Created by jianbai.gbj on 2017/9/14.
+ */
+public class RecyclerTransform {
+
+    public static final String TRANSFORM = Constants.Name.TRANSFORM;
+    private static final Pattern transformPattern = Pattern.compile("([a-z]+)\\(([0-9\\.]+),?([0-9\\.]+)?\\)");
+    private static final String TAG = "RecyclerTransform";
+
+    /**
+     * These transform functions are supported:
+     * - `scale(x,y)`: scale item, x and y should be a positive float number.
+     * - `translate(x,y)`: translate item, `x` and `y` shoule be integer numbers.
+     * - `opacity(n)`: change the transparency of item, `n` must in `[0,1.0]`.
+     * - `rotate(n)`: rotate item, n is integer number.
+     *
+     * @param raw
+     * @return
+     */
+    public static RecyclerView.ItemDecoration parseTransforms(int orientation, String raw) {
+        if (raw == null) {
+            return null;
+        }
+        float scaleX = 0f, scaleY = 0f;
+        int translateX = 0, translateY = 0;
+        float opacity = 0f;
+        int rotate = 0;
+        //public TransformItemDecoration(boolean isVertical,float alpha,int translateX,int translateY,int rotation,float scale)
+        Matcher matcher = transformPattern.matcher(raw);
+        while (matcher.find()) {
+            String match = matcher.group();
+            String name = matcher.group(1);
+            try {
+                switch (name) {
+                    case "scale":
+                        scaleX = Float.parseFloat(matcher.group(2));
+                        scaleY = Float.parseFloat(matcher.group(3));
+                        break;
+                    case "translate":
+                        translateX = Integer.parseInt(matcher.group(2));
+                        translateY = Integer.parseInt(matcher.group(3));
+                        break;
+                    case "opacity":
+                        opacity = Float.parseFloat(matcher.group(2));
+                        break;
+                    case "rotate":
+                        rotate = Integer.parseInt(matcher.group(2));
+                        break;
+                    default:
+                        WXLogUtils.e(TAG, "Invaild transform expression:" + match);
+                        break;
+                }
+            } catch (NumberFormatException e) {
+                WXLogUtils.e("", e);
+                WXLogUtils.e(TAG, "Invaild transform expression:" + match);
+            }
+        }
+        return new TransformItemDecoration(orientation == Constants.Orientation.VERTICAL, opacity, translateX, translateY, rotate, scaleX, scaleY);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/SimpleListComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/SimpleListComponent.java
new file mode 100644
index 0000000..4f3b3d8
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/SimpleListComponent.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.content.Context;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+
+/**
+ * A simple list component based on regular recyclerview, do not support refreshing and loading.
+ * Created by sospartan on 13/12/2016.
+ *
+ */
+public class SimpleListComponent extends BasicListComponent<SimpleRecyclerView>{
+
+  public SimpleListComponent(
+      WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  @Override
+  protected SimpleRecyclerView generateListView(Context context, int orientation) {
+    SimpleRecyclerView view = new SimpleRecyclerView(context);
+    view.initView(context, WXRecyclerView.TYPE_LINEAR_LAYOUT, orientation);
+    return view;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/SimpleRecyclerView.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/SimpleRecyclerView.java
new file mode 100644
index 0000000..f6ea5cc
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/SimpleRecyclerView.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.content.Context;
+
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+import org.apache.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
+
+/**
+ * Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
+ * Created by sospartan on 13/12/2016.
+ */
+
+class SimpleRecyclerView extends WXRecyclerView implements ListComponentView{
+  private RecyclerViewBaseAdapter mAdapter = null;
+
+  public SimpleRecyclerView(Context context) {
+    super(context);
+  }
+
+  @Override
+  public WXRecyclerView getInnerView() {
+    return this;
+  }
+
+  @Override
+  public void setRecyclerViewBaseAdapter(RecyclerViewBaseAdapter adapter) {
+    setAdapter(adapter);
+    this.mAdapter = adapter;
+  }
+
+  /**
+   * @param component
+   */
+  public void notifyStickyShow(WXCell component) {
+    //Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
+  }
+
+  /**
+   * @param component
+   */
+  public void notifyStickyRemove(WXCell component) {
+    //Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
+  }
+
+  @Override
+  public void updateStickyView(int currentStickyPos) {
+    //Simple list is used for specific occasion, NOT Support sticky,load more,bounce etc.
+  }
+
+  @Override
+  public RecyclerViewBaseAdapter getRecyclerViewBaseAdapter() {
+    return mAdapter;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/StickyHeaderHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/StickyHeaderHelper.java
new file mode 100644
index 0000000..8b0efd9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/StickyHeaderHelper.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by sospartan on 17/03/2017.
+ */
+
+public class StickyHeaderHelper {
+  private final ViewGroup mParent;
+  private Map<String,View> mHeaderViews = new HashMap<>(); // map for <ref,view>
+  private Map<String,WXCell> mHeaderComps = new HashMap<>(); // map for <ref,comp>
+  private String mCurrentStickyRef = null;
+
+  public StickyHeaderHelper(ViewGroup parent){
+    this.mParent = parent;
+  }
+
+  /**
+   * @param component
+   */
+  public void notifyStickyShow(WXCell component) {
+    if (component == null)
+      return;
+    mHeaderComps.put(component.getRef(),component);
+    if(mCurrentStickyRef != null){
+      WXCell cell = mHeaderComps.get(mCurrentStickyRef);
+      if(cell ==null || component.getScrollPositon() > cell.getScrollPositon()){
+        mCurrentStickyRef = component.getRef();
+      }
+    }else{
+      mCurrentStickyRef = component.getRef();
+    }
+
+    {
+      if(mCurrentStickyRef==null){
+        WXLogUtils.e("Current Sticky ref is null.");
+        return;
+      }
+
+      WXCell headComponent = mHeaderComps.get(mCurrentStickyRef);
+      final View headerView = headComponent.getRealView();
+      if (headerView == null) {
+        WXLogUtils.e("Sticky header's real view is null.");
+        return;
+      }
+      View header = mHeaderViews.get(headComponent.getRef());
+      if( header != null){
+        //already there
+        header.bringToFront();
+      }else {
+        mHeaderViews.put(headComponent.getRef(), headerView);
+        //record translation, it should not change after transformation
+        final float translationX = headerView.getTranslationX();
+        final float translationY = headerView.getTranslationY();
+        headComponent.removeSticky();
+
+        ViewGroup existedParent;
+        if ((existedParent = (ViewGroup) headerView.getParent()) != null) {
+          existedParent.removeView(headerView);
+        }
+        headerView.setTag(headComponent.getRef());
+        ViewGroup.MarginLayoutParams mlp =
+                new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+        mParent.addView(headerView, mlp);
+        headerView.setTag(this);
+        if(headComponent.getStickyOffset() > 0) {
+          ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) headerView.getLayoutParams();
+          if(headComponent.getStickyOffset() != params.topMargin) {
+            params.topMargin = headComponent.getStickyOffset();
+          }
+        }
+        //recover translation, sometimes it will be changed on fling
+        headerView.setTranslationX(translationX);
+        headerView.setTranslationY(translationY);
+      }
+      changeFrontStickyVisible();
+      if (headComponent.getEvents().contains("sticky")) {
+        headComponent.fireEvent("sticky");
+      }
+    }
+  }
+
+
+  public void notifyStickyRemove(WXCell compToRemove) {
+    if (compToRemove == null)
+      return;
+    final WXCell component = mHeaderComps.containsValue(compToRemove) ? mHeaderComps.remove(compToRemove.getRef()) : compToRemove;
+    final View headerView = mHeaderViews.remove(compToRemove.getRef());
+
+    if(component == null || headerView == null){
+      if(WXEnvironment.isApkDebugable()) {
+      }
+      return;
+    }
+    if(mCurrentStickyRef != null && mCurrentStickyRef.equals(compToRemove.getRef())){
+      mCurrentStickyRef = null;
+    }
+    mParent.post(WXThread.secure(new Runnable() {
+      @Override
+      public void run() {
+        mParent.removeView(headerView);
+        if(headerView.getVisibility() != View.VISIBLE){
+          headerView.setVisibility(View.VISIBLE);
+        }
+        component.recoverySticky();
+        changeFrontStickyVisible();
+
+      }
+    }));
+    if (component.getEvents().contains("unsticky")) {
+      component.fireEvent("unsticky");
+    }
+  }
+
+
+  public void updateStickyView(int currentStickyPos) {
+    Iterator<Map.Entry<String, WXCell>> iterator = mHeaderComps.entrySet().iterator();
+    List<WXCell> toRemove = new ArrayList<>();
+    while(iterator.hasNext()){
+      Map.Entry<String, WXCell> next = iterator.next();
+      WXCell cell = next.getValue();
+      int pos = cell.getScrollPositon();
+      if(pos > currentStickyPos){
+        toRemove.add(cell);
+      }else if(pos == currentStickyPos){
+        mCurrentStickyRef = cell.getRef();
+        View view = mHeaderViews.get(cell.getRef());
+        if(view != null){
+          view.bringToFront();
+          changeFrontStickyVisible();
+        }
+      }
+    }
+    for(WXCell cell:toRemove){
+      notifyStickyRemove(cell);
+    }
+  }
+
+  public void  clearStickyHeaders(){
+    if(mHeaderViews.size() <= 0){
+      return;
+    }
+    Iterator<Map.Entry<String, WXCell>> iterator = mHeaderComps.entrySet().iterator();
+
+    while (iterator.hasNext()) {
+      Map.Entry<String, WXCell> next = iterator.next();
+      WXCell value = next.getValue();
+      iterator.remove();
+      notifyStickyRemove(value);
+    }
+  }
+
+
+  private void changeFrontStickyVisible(){
+    if(mHeaderViews.size() <= 0){
+      return;
+    }
+    boolean  fontVisible = false;
+    for(int i=mParent.getChildCount()-1; i>=0; i--){
+      View view = mParent.getChildAt(i);
+      if(fontVisible && view.getTag() instanceof  StickyHeaderHelper){
+        if(view.getVisibility() != View.GONE){
+          view.setVisibility(View.GONE);
+        }
+      }else{
+        if(view.getTag() instanceof  StickyHeaderHelper){
+          fontVisible = true;
+          if(view != null && view.getVisibility() != View.VISIBLE){
+            view.setVisibility(View.VISIBLE);
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXCell.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXCell.java
new file mode 100644
index 0000000..4efee98
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXCell.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXHeader;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.flat.WidgetContainer;
+import org.apache.weex.ui.view.WXFrameLayout;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import org.apache.weex.common.Constants.Name;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedList;
+
+/**
+ * Root component for components in {@link WXListComponent}
+ */
+@Component(lazyload = false)
+
+public class WXCell extends WidgetContainer<WXFrameLayout> {
+
+    private int mLastLocationY = 0;
+    private ViewGroup mRealView;
+    private View mTempStickyView;
+    private View mHeadView;
+
+    /** used in list sticky detect **/
+    private int mScrollPosition = -1;
+    private boolean mFlatUIEnabled = false;
+
+
+    private Object  renderData;
+
+    private boolean isSourceUsed = false;
+
+    private boolean isAppendTreeDone;
+
+    private CellAppendTreeListener cellAppendTreeListener;
+
+    public static class Creator implements ComponentCreator {
+        public WXComponent createInstance(WXSDKInstance instance,
+                                          WXVContainer parent,
+                                          BasicComponentData basicComponentData)
+                throws IllegalAccessException, InvocationTargetException, InstantiationException {
+            return new WXCell(instance, parent, true, basicComponentData);
+        }
+    }
+
+    @Deprecated
+    public WXCell(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+        super(instance, parent, basicComponentData);
+    }
+
+    public WXCell(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
+        super(instance, parent, basicComponentData);
+        lazy(true);
+        if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP) {
+            try {
+                //TODO a WTF is necessary if anyone try to change the flat flag during update attrs.
+                WXAttr attr = getAttrs();
+                if (attr.containsKey(Constants.Name.FLAT)) {
+                    mFlatUIEnabled = WXUtils.getBoolean(attr.get(Constants.Name.FLAT), false);
+                }
+            } catch (NullPointerException e) {
+                WXLogUtils.e("Cell", WXLogUtils.getStackTrace(e));
+            }
+        }
+        if (!canRecycled()){
+            instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM,1);
+        }
+        if (TextUtils.isEmpty(getAttrs().getScope())){
+            instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_UN_RE_USE_NUM,1);
+        }
+    }
+
+    @Override
+    public boolean isLazy() {
+        return super.isLazy() && !isFixed();
+    }
+
+    @Override
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public boolean isFlatUIEnabled() {
+        return mFlatUIEnabled;
+    }
+
+    /**
+     * If Cell is Sticky, need wraped FrameLayout
+     */
+    @Override
+    protected WXFrameLayout initComponentHostView(@NonNull Context context) {
+        if (isSticky() || this instanceof WXHeader) {
+            WXFrameLayout view = new WXFrameLayout(context);
+            mRealView = new WXFrameLayout(context);
+            view.addView(mRealView);
+            //TODO Maybe there is a better solution for hardware-acceleration view's display list.
+            if (isFlatUIEnabled()) {
+                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+            return view;
+        } else {
+            WXFrameLayout view = new WXFrameLayout(context);
+            mRealView = view;
+            if (isFlatUIEnabled()) {
+                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+            return view;
+        }
+    }
+
+    public int getLocationFromStart(){
+        return mLastLocationY;
+    }
+
+    public void setLocationFromStart(int l){
+        mLastLocationY = l;
+    }
+
+    void setScrollPositon(int pos){
+        mScrollPosition = pos;
+    }
+
+    public int getScrollPositon() {
+        return mScrollPosition;
+    }
+
+    @Override
+    public ViewGroup getRealView() {
+        return mRealView;
+    }
+
+    public void removeSticky() {
+        if(getHostView().getChildCount() > 0) {
+            mHeadView = getHostView().getChildAt(0);
+            int[] location = new int[2];
+            int[] parentLocation = new int[2];
+            getHostView().getLocationOnScreen(location);
+            getParentScroller().getView().getLocationOnScreen(parentLocation);
+            int headerViewOffsetX = location[0] - parentLocation[0];
+            int headerViewOffsetY = getParent().getHostView().getTop();
+            getHostView().removeView(mHeadView);
+            mRealView = (ViewGroup) mHeadView;
+            mTempStickyView = new FrameLayout(getContext());
+            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) getLayoutWidth(),
+                    (int) getLayoutHeight());
+            getHostView().addView(mTempStickyView, lp);
+            mHeadView.setTranslationX(headerViewOffsetX);
+            mHeadView.setTranslationY(headerViewOffsetY);
+        }
+    }
+
+    public void recoverySticky() {
+        if(mHeadView != null){
+            if(mHeadView.getLayoutParams() != null){
+                ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mHeadView.getLayoutParams();
+                if(params.topMargin > 0){
+                    params.topMargin = 0;
+                }
+            }
+            if(mHeadView.getVisibility() != View.VISIBLE){
+                mHeadView.setVisibility(View.VISIBLE);
+            }
+            if(mHeadView.getParent() != null){
+                ((ViewGroup)mHeadView.getParent()).removeView(mHeadView);
+            }
+            getHostView().removeView(mTempStickyView);
+            getHostView().addView(mHeadView);
+            mHeadView.setTranslationX(0);
+            mHeadView.setTranslationY(0);
+        }
+    }
+
+    @Override
+    protected void mountFlatGUI() {
+        if(getHostView()!=null) {
+            if(widgets == null){
+                widgets = new LinkedList<>();
+            }
+            getHostView().mountFlatGUI(widgets);
+        }
+    }
+
+    @Override
+    public void unmountFlatGUI() {
+        if (getHostView() != null) {
+            getHostView().unmountFlatGUI();
+        }
+    }
+
+    @Override
+    public boolean intendToBeFlatContainer() {
+        return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXCell.class.equals(getClass()) && !isSticky();
+    }
+
+    public int getStickyOffset(){
+        if(getAttrs().get(Name.STICKY_OFFSET) == null){
+            return 0;
+        }
+        float  offset = WXUtils.getFloat(getAttrs().get(Name.STICKY_OFFSET));
+        return (int)(WXViewUtils.getRealPxByWidth(offset, getViewPortWidth()));
+    }
+
+    public Object getRenderData() {
+        return renderData;
+    }
+
+    public void setRenderData(Object renderData) {
+        this.renderData = renderData;
+    }
+
+    public boolean isSourceUsed() {
+        return isSourceUsed;
+    }
+
+    public void setSourceUsed(boolean sourceUsed) {
+        isSourceUsed = sourceUsed;
+    }
+
+
+    public boolean isAppendTreeDone(){
+        return isAppendTreeDone;
+    }
+
+    @Override
+    public void appendTreeCreateFinish() {
+        super.appendTreeCreateFinish();
+        isAppendTreeDone = true;
+        if(cellAppendTreeListener != null){
+            cellAppendTreeListener.onAppendTreeDone();
+        }
+    }
+
+    public void setCellAppendTreeListener(CellAppendTreeListener cellAppendTreeListener) {
+        this.cellAppendTreeListener = cellAppendTreeListener;
+        if(isAppendTreeDone){
+            cellAppendTreeListener.onAppendTreeDone();
+        }
+    }
+
+    public interface CellAppendTreeListener{
+        public void onAppendTreeDone();
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXListComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXListComponent.java
new file mode 100644
index 0000000..542d7ad
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXListComponent.java
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.content.Context;
+import android.support.v4.util.ArrayMap;
+import android.support.v7.widget.PagerSnapHelper;
+import android.text.TextUtils;
+import com.alibaba.fastjson.JSON;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXBaseRefresh;
+import org.apache.weex.ui.component.WXBasicComponentType;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXComponentProp;
+import org.apache.weex.ui.component.WXLoading;
+import org.apache.weex.ui.component.WXRefresh;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+import org.apache.weex.ui.view.listview.adapter.ListBaseViewHolder;
+import org.apache.weex.ui.view.refresh.wrapper.BounceRecyclerView;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Unlike other components, there is immutable bi-directional association between View and
+ * ViewHolder, while only mutable and temporal uni-directional association between view and
+ * components. The association only exist from {@link #onBindViewHolder(ListBaseViewHolder, int)} to
+ * {@link #onViewRecycled(ListBaseViewHolder)}. In other situations, the association may not valid
+ * or not even exist.
+ */
+@Component(lazyload = false)
+
+public class WXListComponent extends BasicListComponent<BounceRecyclerView> {
+  private String TAG = "WXListComponent";
+  //  private WXRecyclerDomObject mDomObject;
+  private float mPaddingLeft;
+  private float mPaddingRight;
+  private String mSpanOffsetsStr;
+  private Float[] mSpanOffsets;
+  private boolean hasSetGapItemDecoration = false;
+
+  public static class Creator implements ComponentCreator {
+    public WXComponent createInstance(WXSDKInstance instance,
+                                      WXVContainer parent,
+                                      BasicComponentData basicComponentData)
+            throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      return new WXListComponent(instance, parent, true, basicComponentData);
+    }
+  }
+
+  @Deprecated
+  public WXListComponent(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
+    this(instance, parent, isLazy, basicComponentData);
+  }
+
+
+  public WXListComponent(WXSDKInstance instance, WXVContainer parent, boolean lazy, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  @Override
+  protected BounceRecyclerView generateListView(Context context, int orientation) {
+    BounceRecyclerView bounceRecyclerView = new BounceRecyclerView(context, mLayoutType, mColumnCount, mColumnGap, orientation);
+    if (bounceRecyclerView.getSwipeLayout() != null) {
+      if (WXUtils.getBoolean(getAttrs().get(Constants.Name.NEST_SCROLLING_ENABLED), false)) {
+        bounceRecyclerView.getSwipeLayout().setNestedScrollingEnabled(true);
+      }
+    }
+
+    /**
+     *  enable pagingEnabled attr
+     */
+    if(WXUtils.getBoolean(getAttrs().get(Constants.Name.PAGE_ENABLED),false)){
+      PagerSnapHelper snapHelper = null;
+      String pageSize = WXUtils.getString(getAttrs().get(Constants.Name.PAGE_SIZE), null);
+      if(TextUtils.isEmpty(pageSize)) {
+        snapHelper = new PagerSnapHelper();
+      } else  {
+        snapHelper = new WXPagerSnapHelper();
+      }
+
+      snapHelper.attachToRecyclerView(bounceRecyclerView.getInnerView());
+    }
+
+    return bounceRecyclerView;
+  }
+
+  @Override
+  public void addChild(WXComponent child, int index) {
+    super.addChild(child, index);
+    if (child == null || index < -1) {
+      return;
+    }
+    setRefreshOrLoading(child);
+    // Synchronize DomObject's attr to Component and Native View
+    if(getHostView() != null && hasColumnPros()) {
+      updateRecyclerAttr();
+      getHostView().getInnerView().initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
+    }
+  }
+
+  private boolean hasColumnPros() {
+    return (getAttrs().containsKey(Constants.Name.COLUMN_WIDTH) && mColumnWidth != WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_WIDTH))) ||
+            (getAttrs().containsKey(Constants.Name.COLUMN_COUNT) &&  mColumnCount != WXUtils.parseInt(getAttrs().get(Constants.Name.COLUMN_COUNT))) ||
+            (getAttrs().containsKey(Constants.Name.COLUMN_GAP) && mColumnGap != WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_GAP)));
+  }
+
+  /**
+   * Setting refresh view and loading view
+   *
+   * @param child the refresh_view or loading_view
+   */
+  private boolean setRefreshOrLoading(final WXComponent child) {
+
+    if (getHostView() == null) {
+      WXLogUtils.e(TAG, "setRefreshOrLoading: HostView == null !!!!!! check list attr has append =tree");
+      return true;
+    }
+    if (child instanceof WXRefresh) {
+      getHostView().setOnRefreshListener((WXRefresh) child);
+      getHostView().postDelayed(WXThread.secure(new Runnable() {
+        @Override
+        public void run() {
+          getHostView().setHeaderView(child);
+        }
+      }), 100);
+      return true;
+    }
+
+    if (child instanceof WXLoading) {
+      getHostView().setOnLoadingListener((WXLoading) child);
+      getHostView().postDelayed(WXThread.secure(new Runnable() {
+        @Override
+        public void run() {
+          getHostView().setFooterView(child);
+        }
+      }), 100);
+      return true;
+    }
+    return false;
+  }
+
+  private void updateRecyclerAttr() {
+    mColumnCount = WXUtils.parseInt(getAttrs().get(Constants.Name.COLUMN_COUNT));
+    if (mColumnCount <= 0 && mLayoutType != WXRecyclerView.TYPE_LINEAR_LAYOUT) {
+      Map<String, String> ext = new ArrayMap<>();
+      ext.put("componentType", getComponentType());
+      ext.put("attribute", getAttrs().toString());
+      ext.put("stackTrace", Arrays.toString(Thread.currentThread().getStackTrace()));
+      WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
+          WXErrorCode.WX_RENDER_ERR_LIST_INVALID_COLUMN_COUNT, "columnCount",
+          String.format(Locale.ENGLISH,
+              "You are trying to set the list/recycler/vlist/waterfall's column to %d, which is illegal. The column count should be a positive integer",
+              mColumnCount),
+          ext);
+      mColumnCount = Constants.Value.COLUMN_COUNT_NORMAL;
+    }
+    mColumnGap = WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_GAP));
+    mColumnWidth = WXUtils.parseFloat(getAttrs().get(Constants.Name.COLUMN_WIDTH));
+    mPaddingLeft = WXUtils.parseFloat(getAttrs().get(Constants.Name.PADDING_LEFT));
+    mPaddingRight = WXUtils.parseFloat(getAttrs().get(Constants.Name.PADDING_RIGHT));
+    mSpanOffsetsStr = (String)getAttrs().get(Constants.Name.SPAN_OFFSETS);
+
+    try {
+      if (!TextUtils.isEmpty(mSpanOffsetsStr)) {
+        List<Float> list = JSON.parseArray(mSpanOffsetsStr, Float.class);
+        final int size = list.size();
+        if (null == mSpanOffsets || mSpanOffsets.length != size) {
+          mSpanOffsets = new Float[size];
+        }
+        list.toArray(mSpanOffsets);
+      } else {
+        mSpanOffsets = null;
+      }
+    } catch (Throwable e) {
+      WXLogUtils.w("Parser SpanOffsets error ", e);
+    }
+
+    if (!hasSetGapItemDecoration && null != getSpanOffsets() && null != getHostView()
+        && null != getHostView().getInnerView()) {
+      hasSetGapItemDecoration = true;
+      getHostView().getInnerView().addItemDecoration(new GapItemDecoration(this));
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SPAN_OFFSETS)
+  public void setSpanOffsets(String spanOffsets)  {
+    if (!TextUtils.equals(spanOffsets, mSpanOffsetsStr)) {
+      markComponentUsable();
+      updateRecyclerAttr();
+      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+      wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.COLUMN_WIDTH)
+  public void setColumnWidth(float columnWidth)  {
+    if(columnWidth != mColumnWidth){
+      markComponentUsable();
+      updateRecyclerAttr();
+      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+      wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.COLUMN_COUNT)
+  public void setColumnCount(int columnCount){
+    if(columnCount != mColumnCount) {
+      markComponentUsable();
+      updateRecyclerAttr();
+      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+      wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.COLUMN_GAP)
+  public void setColumnGap(float columnGap) throws InterruptedException {
+    if(columnGap != mColumnGap) {
+      markComponentUsable();
+      updateRecyclerAttr();
+      WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+      wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
+    }
+  }
+
+  @WXComponentProp(name = Constants.Name.SCROLLABLE)
+  public void setScrollable(boolean scrollable) {
+    WXRecyclerView inner = getHostView().getInnerView();
+    inner.setScrollable(scrollable);
+  }
+
+  @Override
+  public void updateProperties(Map<String, Object> props) {
+    super.updateProperties(props);
+    if (isRecycler(this)) {
+      if(WXBasicComponentType.WATERFALL.equals(getComponentType())){
+        mLayoutType = WXRecyclerView.TYPE_STAGGERED_GRID_LAYOUT;
+      }else{
+        mLayoutType = getAttrs().getLayoutType();
+      }
+    }
+
+    if(props.containsKey(Constants.Name.PADDING)
+            ||props.containsKey(Constants.Name.PADDING_LEFT)
+            || props.containsKey(Constants.Name.PADDING_RIGHT)){
+      if(mPaddingLeft != WXUtils.parseFloat(props.get(Constants.Name.PADDING_LEFT)) || mPaddingRight != WXUtils.parseFloat(props.get(Constants.Name.PADDING_RIGHT))) {
+        markComponentUsable();
+        updateRecyclerAttr();
+        WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+        wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
+      }
+    }
+  }
+
+  @Override
+  public void createChildViewAt(int index) {
+    int indexToCreate = index;
+    if (indexToCreate < 0) {
+      indexToCreate = childCount() - 1;
+      if (indexToCreate < 0) {
+        return;
+      }
+    }
+    final WXComponent child = getChild(indexToCreate);
+    if (child instanceof WXBaseRefresh) {
+      child.createView();
+      if (child instanceof WXRefresh) {
+        getHostView().setOnRefreshListener((WXRefresh) child);
+        getHostView().postDelayed(new Runnable() {
+          @Override
+          public void run() {
+            getHostView().setHeaderView(child);
+          }
+        }, 100);
+      } else if (child instanceof WXLoading) {
+        getHostView().setOnLoadingListener((WXLoading) child);
+        getHostView().postDelayed(new Runnable() {
+          @Override
+          public void run() {
+            getHostView().setFooterView(child);
+          }
+        }, 100);
+      }
+    } else {
+      super.createChildViewAt(indexToCreate);
+    }
+  }
+
+  public void remove(WXComponent child, boolean destroy) {
+    super.remove(child, destroy);
+    removeFooterOrHeader(child);
+  }
+
+  private void removeFooterOrHeader(WXComponent child) {
+    if (child instanceof WXLoading) {
+      getHostView().removeFooterView(child);
+    } else if (child instanceof WXRefresh) {
+      getHostView().removeHeaderView(child);
+    }
+  }
+
+  private boolean isRecycler(WXComponent component) {
+    return WXBasicComponentType.WATERFALL.equals(component.getComponentType())
+            || WXBasicComponentType.RECYCLE_LIST.equals(component.getComponentType())
+            || WXBasicComponentType.RECYCLER.equals(component.getComponentType());
+  }
+
+  public Float[] getSpanOffsets() {
+    return mSpanOffsets;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXPagerSnapHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXPagerSnapHelper.java
new file mode 100644
index 0000000..7419aaf
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/WXPagerSnapHelper.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.OrientationHelper;
+import android.support.v7.widget.PagerSnapHelper;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+public class WXPagerSnapHelper extends PagerSnapHelper {
+    @Nullable
+    private OrientationHelper mVerticalHelper;
+    @Nullable
+    private OrientationHelper mHorizontalHelper;
+
+    @Nullable
+    @Override
+    public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
+
+        int[] out = new int[2];
+        if (layoutManager.canScrollHorizontally()) {
+            out[0] = this.distanceToStart(layoutManager, targetView, this.getHorizontalHelper(layoutManager));
+        } else {
+            out[0] = 0;
+        }
+
+        if (layoutManager.canScrollVertically()) {
+            out[1] = this.distanceToStart(layoutManager, targetView, this.getVerticalHelper(layoutManager));
+        } else {
+            out[1] = 0;
+        }
+
+        return out;
+    }
+
+    @NonNull
+    private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
+        if (this.mVerticalHelper == null) {
+            this.mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
+        }
+
+        return this.mVerticalHelper;
+    }
+
+    @NonNull
+    private OrientationHelper getHorizontalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
+        if (this.mHorizontalHelper == null) {
+            this.mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
+        }
+
+        return this.mHorizontalHelper;
+    }
+
+    private int distanceToStart(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
+        return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/AsyncCellLoadTask.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/AsyncCellLoadTask.java
new file mode 100644
index 0000000..098405d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/AsyncCellLoadTask.java
@@ -0,0 +1,129 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import android.os.AsyncTask;
+import android.os.Looper;
+import android.os.MessageQueue;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * Created by furture on 2018/1/25.
+ * async template cell component copy in background and init component when idle
+ */
+class AsyncCellLoadTask extends AsyncTask<Void,Void, Void> {
+
+    private String template;
+    private WXCell source;
+    private WXRecyclerTemplateList templateList;
+
+    public AsyncCellLoadTask(String template, WXCell source, WXRecyclerTemplateList templateList) {
+        this.template = template;
+        this.source = source;
+        this.templateList = templateList;
+    }
+
+    /**
+     * async template cell component copy in background
+     * */
+    @Override
+    protected Void doInBackground(Void... params) {
+        TemplateCache cellCache = templateList.getTemplatesCache().get(template);
+        if(cellCache == null || cellCache.cells == null){
+            return null;
+        }
+        while (cellCache.cells.size() < templateList.getTemplateCacheSize()){
+            long start = System.currentTimeMillis();
+            WXCell component = (WXCell) templateList.copyComponentFromSourceCell(source);
+            if(WXEnvironment.isOpenDebugLog() && WXRecyclerTemplateList.ENABLE_TRACE_LOG){
+                WXLogUtils.d(WXRecyclerTemplateList.TAG, " AsyncCellLoadTask load " + template
+                        + "  " +  component.hashCode()
+                + " used " + (System.currentTimeMillis() - start));
+            }
+            if(component == null){
+                return null;
+            }
+            if(isDestory()){
+                return null;
+            }
+            cellCache.cells.add(component);
+        }
+        return null;
+    }
+
+    /**
+     * init component view when main thread idle
+     * */
+    @Override
+    protected void onPostExecute(Void aVoid) {
+        if(isDestory()){
+            return;
+        }
+        final TemplateCache cellCache = templateList.getTemplatesCache().get(template);
+        if(cellCache == null){
+            return;
+        }
+        if(cellCache.cells == null
+                || cellCache.cells.size() == 0){
+            cellCache.isLoadIng = false;
+            return;
+        }
+        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
+            @Override
+            public boolean queueIdle() {
+                if(isDestory()){
+                    return false;
+                }
+                ConcurrentLinkedQueue<WXCell> queue =  cellCache.cells;
+                Iterator<WXCell> iterator =  queue.iterator();
+                while (iterator.hasNext()){
+                    WXCell component =  iterator.next();
+                    if(component.isLazy()){
+                        templateList.doCreateCellViewBindData(component, template, true);
+                        return iterator.hasNext();
+                    }
+                }
+                return false;
+            }
+        });
+        cellCache.isLoadIng = false;
+    }
+
+    private boolean isDestory(){
+        if(source.getInstance() == null
+                || source.getInstance().isDestroy()){
+            return true;
+        }
+        return templateList.isDestoryed();
+    }
+
+    /**
+     * start cell load task on THREAD_POOL_EXECUTOR
+     * */
+    public void startTask(){
+        executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellDataManager.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellDataManager.java
new file mode 100644
index 0000000..1abfd21
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellDataManager.java
@@ -0,0 +1,271 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSONArray;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by furture on 2018/1/23.
+ * template data manager, manage data and render state
+ */
+public class CellDataManager {
+
+    private static final String VIRTUAL_COMPONENT_SEPRATOR = "@";
+
+    public static final String SUB_COMPONENT_TEMPLATE_ID = "@templateId";
+
+    public static final String VIRTUAL_COMPONENT_ID = "@virtualComponentId";
+
+    /**
+     * template list data, update should vis data manager interface, this field is read only
+     * */
+    JSONArray listData;
+
+    /**
+     * current template list
+     * */
+    public final WXRecyclerTemplateList templateList;
+
+    /**
+     * data render state for position, itemId、dirty、and other info
+     * */
+    private Map<Integer, CellRenderState> renderStates = new ArrayMap<>();
+
+
+    /**
+     * list virtual component data, rendet state
+     * key virtual component id, value is cell render state.
+     * */
+    private Map<String, CellRenderState> virtualComponentRenderStates;
+
+
+
+    /**
+     * template list data manager
+     * */
+    public CellDataManager(WXRecyclerTemplateList templateList) {
+        this.templateList = templateList;
+    }
+
+    /**
+     * get current render state for current position, never return null.
+     * */
+    public CellRenderState getRenderState(int position){
+        CellRenderState renderState = renderStates.get(position);
+        if(renderState == null){
+            renderState = new CellRenderState();
+            renderState.position = position;
+            renderStates.put(position, renderState);
+        }
+        if(position != renderState.position) {
+            renderState.position = position;
+            renderState.hasPositionChange = true;
+        }
+        return renderState;
+    }
+
+    /**
+     * @param  virutalComponentId virutalComponentId
+     * @param  data   update    virutalComponent's data
+     * update virtual component data
+     * */
+    public void updateVirtualComponentData(String virutalComponentId, Object data){
+        if(virtualComponentRenderStates != null){
+            CellRenderState cellRenderState = virtualComponentRenderStates.get(virutalComponentId);
+            if(cellRenderState != null){
+                cellRenderState.getVirtualComponentDatas().put(virutalComponentId, data);
+                cellRenderState.hasVirtualCompoentUpdate = true;
+            }else{
+                if(WXEnvironment.isApkDebugable()) {
+                    throw new IllegalArgumentException("virtualComponentDatas illegal state empty render state" + virutalComponentId);
+                }
+            }
+        }else{
+            if(WXEnvironment.isApkDebugable()){
+                throw  new IllegalArgumentException("virtualComponentDatas illegal state " + virutalComponentId);
+            }
+        }
+    }
+
+    /**
+     * @param  position  current position virtual component
+     * @param  virutalComponentId virutalComponentId
+     * @param  data   update    virutalComponent's data
+     * create virtual component data
+     * */
+    public void createVirtualComponentData(int position, String virutalComponentId, Object data){
+        if(virtualComponentRenderStates == null){
+            virtualComponentRenderStates = new HashMap<>(8);
+        }
+        CellRenderState renderState = renderStates.get(position);
+        renderState.getVirtualComponentDatas().put(virutalComponentId, data);
+        virtualComponentRenderStates.put(virutalComponentId, renderState);
+
+    }
+
+
+
+
+    /**
+     * @param  listData setList data
+     * clear render state for current cell, and virtual component data
+     * */
+    public void setListData(JSONArray listData) {
+        if(this.listData != listData) {
+            if(this.listData != null){
+                if(WXUtils.getBoolean(templateList.getAttrs().get("exitDetach"), true)){
+                    for(int i=0; i<this.listData.size(); i++){
+                        cleanRenderState(renderStates.remove(i));
+                    }
+                }
+            }
+            this.listData = listData;
+            renderStates.clear();
+            if (virtualComponentRenderStates != null) {
+                virtualComponentRenderStates.clear();
+            }
+        }
+    }
+
+    /**
+     * @param index insert index
+     * @param  data  data object
+     * insert data at current index
+     * */
+    public boolean insertData(int index, Object data){
+        listData.add(index, data);
+        boolean renderStateChange = false;
+        for(int i=listData.size(); i>= index; i--){
+            CellRenderState state = renderStates.remove(i);
+            if(state != null){
+                renderStates.put(i + 1, state);
+                renderStateChange = true;
+            }
+        }
+        return renderStateChange;
+    }
+
+    /**
+     *
+     * @param index insert index
+     * @param  data  data object
+     * insert data at current index
+     * */
+    public boolean insertRange(int index, JSONArray data){
+        listData.addAll(index, data);
+        boolean renderStateChange = false;
+        for(int i = listData.size()-1; i >= index; i--){
+            CellRenderState state = renderStates.remove(i);
+            if(state != null){
+                renderStates.put(i + 1, state);
+                renderStateChange = true;
+            }
+        }
+        return renderStateChange;
+    }
+
+    /**
+     * @param  data  data object
+     * @param index insert index
+     * update data, reset new render state,
+     * return true if only data changed, false if viewType changed
+     * */
+    public boolean  updateData(Object data, int index){
+        boolean onlyDataChange = TextUtils.equals(templateList.getTemplateKey(index), templateList.getTemplateKey(data));
+        listData.set(index, data);
+        if(!onlyDataChange){
+            //structure changed, reset render state
+            cleanRenderState(renderStates.remove(index));
+        }else{
+            CellRenderState renderState = renderStates.get(index);
+            if(renderState != null){
+                renderState.hasDataUpdate = true;
+            }
+        }
+        return onlyDataChange;
+    }
+
+    /**
+     * @param index
+     * remove data, and its render state  and  virtual's data
+     * */
+    public void  removeData(Integer index){
+        listData.remove((int)index); //remove by index
+        cleanRenderState(renderStates.remove(index));
+        int count = listData.size() + 1;
+        for(int i=index + 1; i < count; i++){
+            CellRenderState state = renderStates.remove(i);
+            if(state != null){
+                renderStates.put(i-1, state);
+            }
+        }
+    }
+
+    /**
+     *  clean render state, if has virtual component, call virtual component detach lifecycle
+     * */
+    private void  cleanRenderState(CellRenderState renderState){
+        if(renderState == null){
+            return;
+        }
+        if(renderState.hasVirtualComponents()){
+            Collection<String> virtualComponentIds =  renderState.getVirtualComponentIds().values();
+            for(String virtualComponentId : virtualComponentIds){
+                if(virtualComponentRenderStates != null){
+                    virtualComponentRenderStates.remove(virtualComponentId);
+                }
+                WXBridgeManager.getInstance().asyncCallJSEventVoidResult(WXBridgeManager.METHD_COMPONENT_HOOK_SYNC,
+                        templateList.getInstanceId(),
+                        null,
+                        virtualComponentId, VirtualComponentLifecycle.LIFECYCLE, VirtualComponentLifecycle.DETACH, null);
+
+            }
+        }
+    }
+
+
+    /**
+     * create virtualComponentId
+     * */
+    public static String createVirtualComponentId(String listRef, String viewTreeKey, long itemId){
+        return  listRef + VIRTUAL_COMPONENT_SEPRATOR  + viewTreeKey + VIRTUAL_COMPONENT_SEPRATOR + itemId;
+    }
+
+    /**
+     * get list ref from virtualComponentId
+     * */
+    public static String getListRef(String virtualComponentId){
+        if(virtualComponentId == null){
+            return null;
+        }
+        return virtualComponentId.split(VIRTUAL_COMPONENT_SEPRATOR)[0];
+    }
+    
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellRenderContext.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellRenderContext.java
new file mode 100644
index 0000000..9e1c1ca
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellRenderContext.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import org.apache.weex.el.parse.ArrayStack;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by furture on 2018/1/23.
+ * render context for cell template
+ */
+public class CellRenderContext {
+    /**
+     * code execute stack
+     * */
+    public ArrayStack stack = new ArrayStack();
+    /**
+     * init context data
+     * */
+    public Map map = new HashMap(8);
+
+
+    /**
+     * component data context
+     * */
+    public CellRenderState renderState;
+
+    /**
+     * current position
+     * */
+    public int position;
+
+    /**
+     * current list component
+     * */
+    public WXRecyclerTemplateList templateList;
+
+
+    /**
+     * get current render state
+     * */
+    public CellRenderState getRenderState() {
+        if(renderState != null) {
+            renderState =  templateList.getCellDataManager().getRenderState(position);
+        }
+        return renderState;
+    }
+
+
+    public void clear(){
+        if(stack.getList().size() > 0) {
+            stack.getList().clear();
+        }
+        if(map.size() > 0) {
+            map.clear();
+        }
+        renderState  = null;
+        position = 0;
+        templateList = null;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellRenderState.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellRenderState.java
new file mode 100644
index 0000000..1fc0593
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/CellRenderState.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import android.support.v7.widget.RecyclerView;
+
+import org.apache.weex.el.parse.ArrayStack;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by furture on 2018/1/24.
+ * render state for one cell, manage it's render state
+ */
+public class CellRenderState {
+
+    /**
+     * dirty for current position, for example virtual component has update
+     * */
+    boolean hasVirtualCompoentUpdate = false;
+
+    /**
+     * has date update
+     * */
+    boolean hasDataUpdate = false;
+
+    /**
+     * position changed
+     * */
+    boolean hasPositionChange = false;
+
+    /**
+     *  may use position, when position changed should be rendered
+     * */
+    int  position;
+
+    /**
+     * unique itemId for current position, generate via key core
+     * */
+    long itemId = RecyclerView.NO_ID;
+
+
+
+    /**
+     * virtualCompoentId for cell, key is viewTreeKey, value is virutalComponentId.
+     * lazy init,
+     * */
+    private Map<String, String> virtualComponentIds;
+    private Map<String, Object> virtualComponentDatas;
+
+
+    /**
+     * mark once statements has rendered
+     * */
+    private Map<String, ArrayStack> onceComponentStates;
+
+
+    public Map<String, String> getVirtualComponentIds() {
+        if(virtualComponentIds == null){
+            virtualComponentIds = new HashMap<>(8);
+        }
+        return virtualComponentIds;
+    }
+
+    /**
+     * return current cell has virtual component
+     * */
+    public boolean hasVirtualComponents(){
+        return virtualComponentIds != null && virtualComponentIds.size() > 0;
+    }
+
+    public Map<String, Object> getVirtualComponentDatas() {
+        if(virtualComponentDatas == null){
+            virtualComponentDatas = new HashMap<>(4);
+        }
+        return virtualComponentDatas;
+    }
+
+    public Map<String, ArrayStack> getOnceComponentStates() {
+        if(onceComponentStates == null){
+            onceComponentStates = new HashMap<>();
+        }
+        return onceComponentStates;
+    }
+
+    public boolean isDirty() {
+        return hasDataUpdate
+                || hasVirtualCompoentUpdate
+                || hasPositionChange;
+    }
+
+    public boolean isHasDataUpdate() {
+        return hasDataUpdate;
+    }
+
+
+
+    public void  resetDirty(){
+        hasDataUpdate = false;
+        hasVirtualCompoentUpdate = false;
+        hasPositionChange = false;
+    }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/PositionRef.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/PositionRef.java
new file mode 100644
index 0000000..3af1e37
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/PositionRef.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import com.alibaba.fastjson.JSONAware;
+
+/**
+ * position render state, when render state change, position changed
+ * Created by furture on 2018/2/2.
+ */
+public class PositionRef extends  Number implements JSONAware {
+
+    private CellRenderState renderState;
+
+    public PositionRef(CellRenderState renderState) {
+        this.renderState = renderState;
+    }
+
+    @Override
+    public int intValue() {
+        return getPosition();
+    }
+
+    @Override
+    public long longValue() {
+        return getPosition();
+    }
+
+    @Override
+    public float floatValue() {
+        return getPosition();
+    }
+
+    @Override
+    public double doubleValue() {
+        return getPosition();
+    }
+
+    private int getPosition(){
+        if(renderState == null){
+            return  -1;
+        }
+        return renderState.position;
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(getPosition());
+    }
+
+    @Override
+    public String toJSONString() {
+        return String.valueOf(getPosition());
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/Selector.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/Selector.java
new file mode 100644
index 0000000..4564c96
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/Selector.java
@@ -0,0 +1,119 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import android.text.TextUtils;
+
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.component.list.WXCell;
+
+import java.util.List;
+
+/**
+ * Created by furture on 2018/7/24.
+ */
+
+public class Selector {
+
+    /**
+     * @param  selector  [att=xx]
+     * query elements match selector, current only support attr selector
+     * */
+    public static void queryElementAll(WXComponent component, String selector, List<WXComponent> componentList){
+        if(TextUtils.isEmpty(selector)){
+            return;
+        }
+        selector = selector.replaceAll("\\[|]", "");
+        String[] args = selector.split("=");
+        if(args.length <= 0){
+            return;
+        }
+        String key = args[0];
+        String value = null;
+        if(args.length > 1){
+            value = args[1].trim();
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            for(int i=0; i<container.getChildCount(); i++){
+                queryElementAllByAttrs(container.getChild(i), key, value, componentList);
+            }
+        }
+    }
+
+
+    public static void closest(WXComponent component, String selector,List<WXComponent> componentList){
+        if(TextUtils.isEmpty(selector)){
+            return;
+        }
+        selector = selector.replaceAll("\\[|]", "");
+        String[] args = selector.split("=");
+        if(args.length <= 0){
+            return;
+        }
+        String key = args[0];
+        String value = null;
+        if(args.length > 1){
+            value = args[1].trim();
+        }
+        closestByAttrs(component, key, value, componentList);
+    }
+
+    private static void closestByAttrs(WXComponent component, String key, String value, List<WXComponent> componentList){
+        if(matchAttrs(component, key, value)){
+            componentList.add(component);
+        }
+        if(component instanceof WXCell || component instanceof  WXRecyclerTemplateList){
+            return;
+        }
+        queryElementAllByAttrs(component.getParent(), key, value, componentList);
+    }
+
+
+    private static void queryElementAllByAttrs(WXComponent component, String key, String value, List<WXComponent> componentList){
+        if(matchAttrs(component, key, value)){
+            componentList.add(component);
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            for(int i=0; i<container.getChildCount(); i++){
+                queryElementAllByAttrs(container.getChild(i), key, value, componentList);
+            }
+        }
+    }
+
+
+    private static boolean matchAttrs(WXComponent component, String key, String value){
+        if(component.isWaste()){
+            return false;
+        }
+        if(!component.getAttrs().containsKey(key)){
+            return false;
+        }
+        if(TextUtils.isEmpty(value)){
+            return true;
+        }
+        Object attrValue = component.getAttrs().get(key);
+        if(attrValue == null){
+            return false;
+        }
+        return value.equals(attrValue.toString());
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateCache.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateCache.java
new file mode 100644
index 0000000..1021ea7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateCache.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import org.apache.weex.ui.component.list.WXCell;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * preload cell cache
+ * Created by furture on 2017/9/29.
+ */
+class TemplateCache {
+    ConcurrentLinkedQueue<WXCell> cells = new ConcurrentLinkedQueue<>();
+    boolean isLoadIng = false;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateDom.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateDom.java
new file mode 100644
index 0000000..3ab9d33
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateDom.java
@@ -0,0 +1,227 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by furture on 2018/6/27.
+ */
+
+public class TemplateDom {
+
+    public static final String KEY_RESET_ANIMATION = "resetAnimation";
+    public static final String KEY_ATTRS = "attrs";
+    public static final String KEY_TYPE = "type";
+    public static final String KEY_VIRTUAL_DOM_REF = "ref";
+    public static final String VIRTUAL_DOM_IDENTIFY = "[[VirtualElement]]";
+
+
+    public static final String ATTRS_KEY_REF = "ref";
+
+    public static final String ATTACH_CELL_SLOT = "_attach_slot";
+    public static final String DETACH_CELL_SLOT = "_detach_slot";
+
+    public static final char SEPARATOR = '@';
+
+
+    public static String genKeyVirtualDomRef(String listRef, int position, String key){
+        return listRef + SEPARATOR + position + SEPARATOR  +  key;
+    }
+
+    public static WXComponent findVirtualComponentByVRef(String pageId, String virtualRef) {
+        try{
+
+            String[]  segments = virtualRef.split(SEPARATOR + "");
+            String listRef = segments[0]; // list ref
+            WXComponent component = WXSDKManager
+                .getInstance().getWXRenderManager().getWXComponent(pageId, listRef);
+            if(!(component instanceof WXRecyclerTemplateList)){
+                return null;
+            }
+            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) component;
+            if(templateList.getHostView() == null || templateList.getHostView().getInnerView() == null){
+                return null;
+            }
+            int position = Integer.parseInt(segments[1]); // position
+            WXRecyclerView recyclerView = templateList.getHostView().getInnerView();
+            TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(position);
+            if(itemHolder == null){
+                return null;
+            }
+
+            WXCell cell = itemHolder.getTemplate();
+            String viewKey = segments[2]; //viewkey
+            WXComponent target = findComponentByViewTreeKey(cell, viewKey);
+            return  target;
+        }catch (Exception e){
+            return  null;
+        }
+    }
+
+    /**
+     * find all component that contains ref attr
+     * */
+    public static Map<String,Object> findAllComponentRefs(String listRef, int position , WXComponent component){
+        Map<String,Object> refs = new HashMap<>();
+        findAllComponentRefs(listRef, position, component, refs);
+        Map<String,Object> refsMap = new HashMap<>();
+        refsMap.put("refs", refs);
+        refsMap.put("position", position);
+        refsMap.put("listRef", listRef);
+        return refsMap;
+    }
+
+    private static void findAllComponentRefs(String listRef, int position, WXComponent component, Map<String,Object> refs){
+        if(component.isWaste()){
+            return;
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            for(int i=0; i<container.getChildCount(); i++){
+                WXComponent child = container.getChild(i);
+                findAllComponentRefs(listRef, position, child, refs);
+            }
+        }
+        WXAttr attrs = component.getAttrs();
+        if(attrs != null
+                && attrs.get(TemplateDom.ATTRS_KEY_REF) == null){
+            return;
+        }
+        String ref  = attrs.get(TemplateDom.ATTRS_KEY_REF).toString();
+        List<Object> refList = (List<Object>) refs.get(ref);
+        if(refList == null){
+            refList = new ArrayList<>();
+            refs.put(ref, refList);
+        }
+        Map map = toMap(listRef, position, component);
+        refList.add(map);
+    }
+
+
+    public static Map toMap(String listRef, int position, WXComponent component){
+        Map map = new HashMap();
+        map.put(TemplateDom.KEY_ATTRS, component.getAttrs());
+        map.put(TemplateDom.KEY_TYPE, component.getComponentType());
+        map.put(TemplateDom.KEY_VIRTUAL_DOM_REF, TemplateDom.genKeyVirtualDomRef(listRef, position, component.getViewTreeKey()));
+        map.put(VIRTUAL_DOM_IDENTIFY, true);
+        return map;
+    }
+
+
+    public static boolean isVirtualDomRef(String ref){
+        if(ref != null){
+            return  ref.indexOf(SEPARATOR) > 0;
+        }
+        return  false;
+    }
+
+
+    public static void resetAnimaiton(View view){
+        if(view == null){
+            return;
+        }
+        if(ViewCompat.getTranslationX(view) != 0){
+            ViewCompat.setTranslationX(view, 0);
+        }
+
+        if(ViewCompat.getTranslationY(view) != 0){
+            ViewCompat.setTranslationY(view, 0);
+        }
+
+        if(ViewCompat.getTranslationZ(view) != 0){
+            ViewCompat.setTranslationZ(view, 0);
+        }
+
+        if(ViewCompat.getScaleX(view) != 1.0f){
+            ViewCompat.setScaleX(view, 1.0f);
+        }
+
+        if(ViewCompat.getScaleY(view) != 1.0f){
+            ViewCompat.setScaleY(view, 1.0f);
+        }
+
+        if(ViewCompat.getRotationX(view) != 0){
+            ViewCompat.setRotationX(view, 0);
+        }
+
+        if(ViewCompat.getRotationY(view) != 0){
+            ViewCompat.setRotationY(view, 0);
+        }
+
+        if(ViewCompat.getElevation(view) != 0){
+            ViewCompat.setElevation(view, 0);
+        }
+    }
+
+
+    /**
+     * find child list, has same ref
+     * */
+    public static final  WXComponent findComponentByViewTreeKey(WXComponent component, String viewKey){
+        if(component.getViewTreeKey().equals(viewKey)){
+            return component;
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            for(int i=0; i<container.getChildCount(); i++){
+                WXComponent element = container.getChild(i);
+                if(findComponentByViewTreeKey(element, viewKey) != null){
+                    return element;
+                }
+            }
+
+        }
+        return null;
+    }
+
+    /**
+     * find child by ref
+     * */
+    private  static WXComponent findChildByAttrsRef(WXComponent component, String ref){
+        if(component.getAttrs() != null && ref.equals(component.getAttrs().get(TemplateDom.ATTRS_KEY_REF))){
+            return component;
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            for(int i=0; i<container.getChildCount(); i++){
+                WXComponent child = findChildByAttrsRef(container.getChild(i), ref);
+                if(child != null){
+                    return  child;
+                }
+            }
+        }
+        return  null;
+    }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateStickyHelper.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateStickyHelper.java
new file mode 100644
index 0000000..e0630f5
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateStickyHelper.java
@@ -0,0 +1,250 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import android.support.v4.util.ArrayMap;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.view.refresh.wrapper.BounceRecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * StickyHelper For Template List
+ * Created by furture on 2017/8/24.
+ */
+public class TemplateStickyHelper {
+    private WXRecyclerTemplateList recyclerTemplateList;
+    private List<Integer> stickyPositions;
+    private ArrayMap<Integer, TemplateViewHolder>   stickyHolderCache;
+    private List<String> mStickyTypes;
+
+
+    public TemplateStickyHelper(WXRecyclerTemplateList recyclerTemplateList) {
+        this.recyclerTemplateList = recyclerTemplateList;
+        this.stickyPositions = new ArrayList<>();
+        this.stickyHolderCache = new ArrayMap();
+        this.mStickyTypes = new ArrayList<>(8);
+    }
+
+    /**
+     * dispatch scroll event, sticky  header
+     * */
+    public void onBeforeScroll(int dx, int dy) {
+        if(stickyPositions == null || stickyPositions.size() == 0){
+           return;
+        }
+        BounceRecyclerView bounceRecyclerView = recyclerTemplateList.getHostView();
+        RecyclerView recyclerView = recyclerTemplateList.getHostView().getInnerView();
+        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+        int firstVisiblePosition = -1;
+        int lastVisiblePosition = -1;
+        if (layoutManager instanceof LinearLayoutManager) {
+            firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+            lastVisiblePosition  = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
+        }else if (layoutManager instanceof StaggeredGridLayoutManager) {
+            int [] firstVisibleItemPositions = new int[3];//max 3 column
+            firstVisiblePosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(firstVisibleItemPositions)[0];
+            lastVisiblePosition = ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(firstVisibleItemPositions)[0];
+        }
+        if(firstVisiblePosition < 0){
+            return;
+        }
+
+        TemplateViewHolder firstVisibleItemHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(firstVisiblePosition);
+        if(firstVisibleItemHolder == null){
+            return;
+        }
+
+        //find match sticky position
+        int matchStickyPosition = -1;
+        for (Integer headerPosition : stickyPositions){
+            if(headerPosition == null){
+                continue;
+            }
+            if(headerPosition <= firstVisiblePosition){
+                matchStickyPosition = Math.max(matchStickyPosition, headerPosition);
+            }else{
+                break;
+            }
+        }
+        if(matchStickyPosition < 0){
+            //remove holder for match position not found
+            View stickyFakeView = bounceRecyclerView.getChildAt(bounceRecyclerView.getChildCount() - 1);
+            if(stickyFakeView.getTag() instanceof TemplateViewHolder){
+                TemplateViewHolder stickyFakeViewHolder = (TemplateViewHolder) stickyFakeView.getTag();
+                bounceRecyclerView.removeView(stickyFakeViewHolder.itemView);
+                stickyFakeViewHolder.itemView.setTranslationY(0);
+                if(stickyFakeViewHolder.getComponent() != null
+                        && stickyFakeViewHolder.getComponent().getEvents().contains(Constants.Event.UNSTICKY)){
+                    stickyFakeViewHolder.getComponent().fireEvent(Constants.Event.UNSTICKY);
+                }
+            }
+
+            /**check has sticky cell not visible */
+            for(int i=0; i<recyclerView.getChildCount(); i++) {
+                View itemView = recyclerView.getChildAt(i);
+                TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.getChildViewHolder(itemView);
+                if (itemHolder == null) {
+                    continue;
+                }
+                int adapterPosition = itemHolder.getAdapterPosition();
+                if (!stickyPositions.contains(adapterPosition)) {
+                    continue;
+                }
+                if(itemView.getVisibility() != View.VISIBLE) {
+                    itemView.setVisibility(View.VISIBLE);
+                }
+            }
+            return;
+        }
+
+        //onCreate holder for match position if not exist
+        View stickyFakeView = bounceRecyclerView.getChildAt(bounceRecyclerView.getChildCount() - 1);
+        if(!(stickyFakeView.getTag() instanceof TemplateViewHolder)
+                || ((TemplateViewHolder) stickyFakeView.getTag()).getHolderPosition() != matchStickyPosition){
+
+             //remove previous sticky header
+            if(stickyFakeView.getTag() instanceof TemplateViewHolder &&
+                    ((TemplateViewHolder) stickyFakeView.getTag()).getHolderPosition() != matchStickyPosition){
+                TemplateViewHolder stickyFakeViewHolder = (TemplateViewHolder) stickyFakeView.getTag();
+                bounceRecyclerView.removeView(stickyFakeViewHolder.itemView);
+                stickyFakeViewHolder.itemView.setTranslationY(0);
+                if(stickyFakeViewHolder.getComponent() != null
+                        && stickyFakeViewHolder.getComponent().getEvents().contains(Constants.Event.UNSTICKY)){
+                    stickyFakeViewHolder.getComponent().fireEvent(Constants.Event.UNSTICKY);
+                }
+            }
+
+            //onCreate new sticky
+            int stickyHolderType = recyclerTemplateList.getItemViewType(matchStickyPosition);
+            TemplateViewHolder fakeStickyHolder = stickyHolderCache.get(stickyHolderType);
+            if(fakeStickyHolder == null){
+                fakeStickyHolder = recyclerTemplateList.onCreateViewHolder(recyclerView, stickyHolderType);
+                stickyHolderCache.put(stickyHolderType, fakeStickyHolder);
+            }
+            recyclerTemplateList.onBindViewHolder(fakeStickyHolder, matchStickyPosition);
+            fakeStickyHolder.itemView.setTranslationY(0);
+            fakeStickyHolder.itemView.setTag(fakeStickyHolder);
+            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+            fakeStickyHolder.getComponent().clearPreLayout();
+            if(fakeStickyHolder.itemView.getParent() != null){
+                ViewGroup parent = (ViewGroup) fakeStickyHolder.itemView.getParent();
+                parent.removeView(fakeStickyHolder.itemView);
+            }
+            bounceRecyclerView.addView(fakeStickyHolder.itemView, params);
+            fakeStickyHolder.getComponent().setLayout(fakeStickyHolder.getComponent());
+            stickyFakeView = fakeStickyHolder.itemView;
+            if(fakeStickyHolder.getComponent() != null
+                    && fakeStickyHolder.getComponent().getEvents().contains(Constants.Event.STICKY)){
+                fakeStickyHolder.getComponent().fireEvent(Constants.Event.STICKY);
+            }
+        }
+        TemplateViewHolder stickyFakeViewHolder = (TemplateViewHolder) stickyFakeView.getTag();
+        for(int i=0; i<recyclerView.getChildCount(); i++){
+            View itemView = recyclerView.getChildAt(i);
+            TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.getChildViewHolder(itemView);
+            if(itemHolder == null){
+                continue;
+            }
+            int adapterPosition = itemHolder.getAdapterPosition();
+            if(!stickyPositions.contains(adapterPosition)){
+                continue;
+            }
+            if(adapterPosition == stickyFakeViewHolder.getHolderPosition()){
+                if(itemView.getVisibility() != View.INVISIBLE) {
+                    itemView.setVisibility(View.INVISIBLE);
+                }
+            }else{
+                if(itemView.getVisibility() != View.VISIBLE) {
+                    itemView.setVisibility(View.VISIBLE);
+                }
+            }
+        }
+
+        if(firstVisibleItemHolder.getComponent().isSticky()){
+            if(firstVisibleItemHolder.itemView.getY() < 0){
+                if(firstVisibleItemHolder.itemView.getVisibility() != View.INVISIBLE) {
+                    firstVisibleItemHolder.itemView.setVisibility(View.INVISIBLE);
+                }
+                if(stickyFakeView.getVisibility() != View.VISIBLE) {
+                    stickyFakeView.setVisibility(View.VISIBLE);
+                }
+                stickyFakeView.bringToFront();
+            }else{
+                if(firstVisibleItemHolder.itemView.getVisibility() != View.VISIBLE) {
+                    firstVisibleItemHolder.itemView.setVisibility(View.VISIBLE);
+                }
+                if(stickyFakeView.getVisibility() != View.GONE) {
+                    stickyFakeView.setVisibility(View.GONE);
+                }
+            }
+        }else{
+            if(stickyFakeView.getVisibility() != View.VISIBLE){
+                stickyFakeView.setVisibility(View.VISIBLE);
+            }
+        }
+
+        //handle sticky is related, find next sticky position on screen
+        int nextVisiblePostion = firstVisiblePosition + 1;
+        if(lastVisiblePosition > 0){
+            for(int i=nextVisiblePostion; i<= lastVisiblePosition; i++){
+                if(stickyPositions.contains(i)){
+                    nextVisiblePostion = i;
+                    break;
+                }
+            }
+        }
+        if(!stickyPositions.contains(nextVisiblePostion)){
+            if(stickyFakeViewHolder.itemView.getTranslationY() < 0){
+                stickyFakeViewHolder.itemView.setTranslationY(0);
+            }
+            return;
+        }
+        TemplateViewHolder nextStickyHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(nextVisiblePostion);
+        if(nextStickyHolder == null
+                || nextStickyHolder.getComponent() == null){
+            return;
+        }
+        int translationY = (int)(nextStickyHolder.itemView.getY() - stickyFakeViewHolder.itemView.getMeasuredHeight());
+        if(translationY <= 0){
+            stickyFakeViewHolder.itemView.setTranslationY(translationY);
+        }else{
+            stickyFakeViewHolder.itemView.setTranslationY(0);
+        }
+    }
+
+    public List<Integer> getStickyPositions() {
+        if(stickyPositions == null){
+            stickyPositions = new ArrayList<>();
+        }
+        return stickyPositions;
+    }
+
+    public List<String> getStickyTypes() {
+        return mStickyTypes;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateViewHolder.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateViewHolder.java
new file mode 100644
index 0000000..0742a80
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/TemplateViewHolder.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import android.os.AsyncTask;
+import android.view.View;
+
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.view.listview.adapter.ListBaseViewHolder;
+
+/**
+ * Created by furture on 2017/8/17.
+ */
+
+public class TemplateViewHolder extends ListBaseViewHolder {
+
+    /**
+     * strong reference, prevent recycled
+     * */
+    private WXCell template;
+
+    private WXRecyclerTemplateList templateList;
+
+    private int holderPosition = -1;
+
+    public AsyncTask<Void, Void, Void> asyncTask;
+
+    public Object  data;
+
+    /**
+     * header position
+     * */
+
+    public TemplateViewHolder(WXRecyclerTemplateList templateList, WXCell component, int viewType) {
+        super(component, viewType);
+        this.template = component;
+        this.templateList = templateList;
+    }
+
+    public TemplateViewHolder(WXRecyclerTemplateList templateList, View view, int viewType) {
+        super(view, viewType);
+        this.templateList = templateList;
+    }
+
+
+
+
+    public int getHolderPosition() {
+        return holderPosition;
+    }
+
+    public void setHolderPosition(int holderPosition) {
+        this.holderPosition = holderPosition;
+    }
+
+    public WXCell getTemplate() {
+        return template;
+    }
+
+    public WXRecyclerTemplateList getTemplateList() {
+        return templateList;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/VirtualComponentLifecycle.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/VirtualComponentLifecycle.java
new file mode 100644
index 0000000..30fbfcf
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/VirtualComponentLifecycle.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+
+/**
+ * Created by furture on 2018/2/1.
+ */
+
+public class VirtualComponentLifecycle {
+
+    /**
+     * lifecycle
+     * */
+    public static final  String LIFECYCLE = "lifecycle";
+
+
+    /**
+     * virtual component lifecycle
+     * */
+    public static final  String CREATE = "create";
+
+    public static final  String ATTACH = "attach";
+
+    public static final  String SYNSTATE = "syncState";
+
+    public static final  String DETACH = "detach";
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/WXRecyclerTemplateList.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/WXRecyclerTemplateList.java
new file mode 100644
index 0000000..4cd5311
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/WXRecyclerTemplateList.java
@@ -0,0 +1,2019 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.os.Build;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.annotation.Component;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.ICheckBindingScroller;
+import org.apache.weex.common.OnWXScrollListener;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.el.parse.ArrayStack;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.AppearanceHelper;
+import org.apache.weex.ui.component.Scrollable;
+import org.apache.weex.ui.component.WXBaseRefresh;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXComponentProp;
+import org.apache.weex.ui.component.WXLoading;
+import org.apache.weex.ui.component.WXRefresh;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.component.binding.Layouts;
+import org.apache.weex.ui.component.binding.Statements;
+import org.apache.weex.ui.component.helper.ScrollStartEndHelper;
+import org.apache.weex.ui.component.list.RecyclerTransform;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+import org.apache.weex.ui.view.listview.adapter.IOnLoadMoreListener;
+import org.apache.weex.ui.view.listview.adapter.IRecyclerAdapterListener;
+import org.apache.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
+import org.apache.weex.ui.view.listview.adapter.WXRecyclerViewOnScrollListener;
+import org.apache.weex.ui.view.refresh.wrapper.BounceRecyclerView;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.weex.common.Constants.Name;
+
+/**
+ * weex template list supported, high performance recycler-list
+ * https://github.com/Hanks10100/weex-native-directive
+ * Created by jianbai.gbj on 2017/8/17.
+ */
+@Component(lazyload = false)
+public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> implements
+    IRecyclerAdapterListener<TemplateViewHolder>, IOnLoadMoreListener, Scrollable {
+
+    /**
+     * trace log for template list
+     * */
+    public static final boolean ENABLE_TRACE_LOG = false;
+
+    public static final String TAG = "WXRecyclerTemplateList";
+
+    private static final String EMPTY_HOLDER_TEMPLATE_KEY  = "";
+    private static final String NAME_HAS_FIXED_SIZE = "hasFixedSize";
+    private static final String NAME_ITEM_VIEW_CACHE_SIZE = "itemViewCacheSize";
+    private static final String NAME_TEMPLATE_CACHE_SIZE = "templateCacheSize";
+
+    // TODO
+//    private WXRecyclerDomObject mDomObject;
+    protected int mLayoutType = WXRecyclerView.TYPE_LINEAR_LAYOUT;
+    protected int mColumnCount = 1;
+    protected float mColumnGap = 0;
+    protected float mColumnWidth = 0;
+    private float mPaddingLeft;
+    private float mPaddingRight;
+
+    private WXRecyclerViewOnScrollListener mViewOnScrollListener = new WXRecyclerViewOnScrollListener(this);
+    private int mListCellCount = 0;
+    private boolean mForceLoadmoreNextTime = false;
+    private RecyclerView.ItemAnimator mItemAnimator;
+
+    /**
+     * default orientation
+     * */
+    private  int orientation = Constants.Orientation.VERTICAL;
+
+    /**
+     * offset reported
+     * */
+    private boolean isScrollable = true;
+    private int mOffsetAccuracy = 10;
+    private Point mLastReport = new Point(-1, -1);
+    private boolean mHasAddScrollEvent = false;
+
+
+    private CellDataManager cellDataManager;
+    private String listDataKey = Constants.Name.Recycler.LIST_DATA;
+    private String listDataItemKey = null;
+    private String listDataIndexKey = null;
+    private ArrayMap<String, Integer> mTemplateViewTypes;
+
+
+    private Map<String, WXCell> mTemplateSources;
+    private String  listDataTemplateKey = Constants.Name.Recycler.SLOT_TEMPLATE_CASE;
+    private Runnable listUpdateRunnable;
+    private ConcurrentHashMap<String, TemplateCache> mTemplatesCache;
+    private int templateCacheSize = 2;
+
+
+    /**
+     * case default cell and key
+     * */
+    private WXCell defaultTemplateCell;
+    private String defaultTemplateKey = "@default_template_cell";
+
+    /**
+     * scroll start and scroll end event
+     * */
+    private ScrollStartEndHelper mScrollStartEndHelper;
+
+
+    /**
+     * sticky helper
+     * */
+    private TemplateStickyHelper mStickyHelper;
+
+
+    /**
+     * appear and disappear event managaer
+     * */
+    private ArrayMap<Integer, List<AppearanceHelper>> mAppearHelpers = new ArrayMap<>();
+
+    /**
+     * disappear event will be fire,
+     * fist layer map key position,
+     * send layer map key String ref
+     * three layer map key view hash code, value is event arguments
+     * */
+    private ArrayMap<Integer, Map<String,Map<Integer, List<Object>>>> mDisAppearWatchList = new ArrayMap<>();
+
+    private CellRenderContext cellRenderContext = new CellRenderContext();
+
+    private Runnable mAppearChangeRunnable = null;
+    private static final long APPEAR_CHANGE_RUNNABLE_DELAY = 50;
+
+    /**
+     * has append tree done
+     * */
+    private boolean hasAppendTreeDone = false;
+
+    /**
+     * has layout done
+     * */
+    private boolean hasLayoutDone = false;
+
+    public WXRecyclerTemplateList(
+        WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+        super(instance, parent, basicComponentData);
+        initRecyclerTemplateList(instance, basicComponentData, parent);
+    }
+
+    private void initRecyclerTemplateList(WXSDKInstance instance, BasicComponentData basicComponentData,
+                                          WXVContainer parent){
+
+        updateRecyclerAttr();
+
+        mTemplateViewTypes = new ArrayMap<>();
+        mTemplateViewTypes.put(EMPTY_HOLDER_TEMPLATE_KEY, 0); //empty view, when template was not sended
+        mTemplateSources = new HashMap<>();
+        mTemplatesCache = new ConcurrentHashMap<>();
+        mStickyHelper = new TemplateStickyHelper(this);
+        orientation =  basicComponentData.getAttrs().getOrientation();
+        listDataTemplateKey = WXUtils.getString(getAttrs().get(Constants.Name.Recycler.LIST_DATA_TEMPLATE_SWITCH_KEY), Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
+        listDataItemKey = WXUtils.getString(getAttrs().get(Constants.Name.Recycler.LIST_DATA_ITEM), listDataItemKey);
+        listDataIndexKey = WXUtils.getString(getAttrs().get(Constants.Name.Recycler.LIST_DATA_ITEM_INDEX), listDataIndexKey);
+        cellDataManager = new CellDataManager(this);
+        cellDataManager.listData = parseListDataToJSONArray(getAttrs().get(Constants.Name.Recycler.LIST_DATA));
+        /**
+         * we have separate cell with list, post add cell in dom thread ensure
+         * list has layout and can archive better user experience and better load time,
+         * which reduce waste cell layout when list layout changes.
+         * */
+        // TODO
+//        if(mDomObject != null
+//                && mDomObject.getCellList() != null
+//                && mDomObject.getCellList().size() > 0){
+//            Runnable runnable =  new Runnable() {
+//                // @Override
+//                public void run() {
+//                    if(isDestoryed()){
+//                        return;
+//                    }
+//                    long start = System.currentTimeMillis();
+//                    if(mDomObject != null && mDomObject.getCellList() != null){
+//                        for(int i=0; i<mDomObject.getCellList().size(); i++){
+//                            addChild(ComponentUtils.buildTree(mDomObject.getCellList().get(i),  WXRecyclerTemplateList.this));
+//                        }
+//                    }
+//                    if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
+//                        WXLogUtils.d(TAG, "TemplateList BuildDomTree Used " + (System.currentTimeMillis() - start));
+//                    }
+//                }
+//            };
+//            WXSDKManager.getInstance().getWXDomManager().post(runnable);
+//        }
+    }
+
+    @Override
+    protected BounceRecyclerView initComponentHostView(@NonNull Context context) {
+        final BounceRecyclerView bounceRecyclerView = new BounceRecyclerView(context,mLayoutType,mColumnCount,mColumnGap, getOrientation());
+        WXAttr attrs = getAttrs();
+        String transforms = (String) attrs.get(Constants.Name.TRANSFORM);
+        if (transforms != null) {
+            bounceRecyclerView.getInnerView().addItemDecoration(
+                RecyclerTransform.parseTransforms(getOrientation(), transforms));
+        }
+        mItemAnimator = bounceRecyclerView.getInnerView().getItemAnimator();
+
+        if(attrs.get(NAME_TEMPLATE_CACHE_SIZE) != null){
+            templateCacheSize =  WXUtils.getInteger(attrs.get(NAME_TEMPLATE_CACHE_SIZE), templateCacheSize);
+        }
+
+        boolean hasFixedSize = false;
+        int itemViewCacheSize = 2;
+        if(attrs.get(NAME_ITEM_VIEW_CACHE_SIZE) != null){
+            itemViewCacheSize = WXUtils.getNumberInt(getAttrs().get(NAME_ITEM_VIEW_CACHE_SIZE), itemViewCacheSize);
+        }
+        if(attrs.get(NAME_HAS_FIXED_SIZE) != null){
+            hasFixedSize =  WXUtils.getBoolean(attrs.get(NAME_HAS_FIXED_SIZE), hasFixedSize);
+        }
+        RecyclerViewBaseAdapter recyclerViewBaseAdapter = new RecyclerViewBaseAdapter<>(this);
+        recyclerViewBaseAdapter.setHasStableIds(true);
+        bounceRecyclerView.getInnerView().setItemAnimator(null);
+        if(itemViewCacheSize != 2) {
+            bounceRecyclerView.getInnerView().setItemViewCacheSize(itemViewCacheSize);
+        }
+        if(bounceRecyclerView.getSwipeLayout()  != null){
+            if(WXUtils.getBoolean(getAttrs().get("nestedScrollingEnabled"), false)) {
+                bounceRecyclerView.getSwipeLayout().setNestedScrollingEnabled(true);
+            }
+        }
+        bounceRecyclerView.getInnerView().setHasFixedSize(hasFixedSize);
+        bounceRecyclerView.setRecyclerViewBaseAdapter(recyclerViewBaseAdapter);
+        bounceRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
+        bounceRecyclerView.getInnerView().clearOnScrollListeners();
+        bounceRecyclerView.getInnerView().addOnScrollListener(mViewOnScrollListener);
+        bounceRecyclerView.getInnerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                super.onScrollStateChanged(recyclerView, newState);
+                getScrollStartEndHelper().onScrollStateChanged(newState);
+                List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
+                if (listeners != null && listeners.size() > 0) {
+                    for (OnWXScrollListener listener : listeners) {
+                        if (listener != null) {
+                            View topView = recyclerView.getChildAt(0);
+                            if (topView != null) {
+                                int y = topView.getTop();
+                                listener.onScrollStateChanged(recyclerView, 0, y, newState);
+                            }
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                super.onScrolled(recyclerView, dx, dy);
+                List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
+                if (listeners != null && listeners.size() > 0) {
+                    try {
+                        for (OnWXScrollListener listener : listeners) {
+                            if (listener != null) {
+                                if (listener instanceof ICheckBindingScroller) {
+                                    if (((ICheckBindingScroller) listener).isNeedScroller(getRef(), null)) {
+                                        listener.onScrolled(recyclerView, dx, dy);
+                                    }
+                                } else {
+                                    listener.onScrolled(recyclerView, dx, dy);
+                                }
+                            }
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        });
+        bounceRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+            @Override
+            public void onGlobalLayout() {
+                BounceRecyclerView view;
+                if ((view = getHostView()) == null)
+                    return;
+                mViewOnScrollListener.onScrolled(view.getInnerView(), 0, 0);
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                    view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                } else {
+                    view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+                }
+            }
+        });
+        listUpdateRunnable = new Runnable() {
+            @Override
+            public void run() {
+                /**
+                 * compute sticky position
+                 * */
+                if(mStickyHelper != null){
+                    if(mStickyHelper.getStickyTypes().size() > 0){
+                        mStickyHelper.getStickyPositions().clear();
+                        if(cellDataManager.listData != null){
+                            for(int i = 0; i< cellDataManager.listData.size(); i++){
+                                WXCell cell = getSourceTemplate(i);
+                                if(cell == null){
+                                    continue;
+                                }
+                                if(cell.isSticky()){
+                                    mStickyHelper.getStickyPositions().add(i);
+                                }
+                            }
+                        }
+                    }
+                }
+                if(getHostView() != null && getHostView().getRecyclerViewBaseAdapter() != null){
+                    getHostView().getRecyclerViewBaseAdapter().notifyDataSetChanged();
+                }
+                if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
+                    WXLogUtils.d(TAG, "WXTemplateList notifyDataSetChanged");
+                }
+            }
+        };
+        return bounceRecyclerView;
+    }
+
+
+
+
+    @Override
+    protected void onHostViewInitialized(BounceRecyclerView host) {
+        super.onHostViewInitialized(host);
+        WXRecyclerView recyclerView = host.getInnerView();
+        if (recyclerView == null || recyclerView.getAdapter() == null) {
+            WXLogUtils.e(TAG, "RecyclerView is not found or Adapter is not bound");
+            return;
+        }
+    }
+
+    /**
+     * Measure the size of the recyclerView.
+     *
+     * @param width  the expected width
+     * @param height the expected height
+     * @return the result of measurement
+     */
+    @Override
+    protected MeasureOutput measure(int width, int height) {
+        int screenH = WXViewUtils.getScreenHeight(WXEnvironment.sApplication);
+        int weexH = WXViewUtils.getWeexHeight(getInstanceId());
+        int outHeight = height > (weexH >= screenH ? screenH : weexH) ? weexH - getAbsoluteY() : height;
+        return super.measure(width, outHeight);
+    }
+
+
+    @Override
+    public void bindStickStyle(WXComponent component) {
+        WXComponent template = findParentType(component, WXCell.class);
+        if(template == null){
+            return;
+        }
+        if(mStickyHelper == null){
+            return;
+        }
+        if(!mStickyHelper.getStickyTypes().contains(template.getRef())){
+            mStickyHelper.getStickyTypes().add(template.getRef());
+            notifyUpdateList();
+        }
+    }
+
+    @Override
+    public void unbindStickStyle(WXComponent component) {
+        WXComponent template = findParentType(component, WXCell.class);
+        if(template == null
+                || mStickyHelper == null){
+            return;
+        }
+        if(mStickyHelper.getStickyTypes().contains(template.getRef())){
+            mStickyHelper.getStickyTypes().remove(template.getRef());
+            notifyUpdateList();
+        }
+    }
+
+    private @Nullable
+    WXCell findCell(WXComponent component) {
+        if(component instanceof WXCell){
+            return (WXCell) component;
+        }
+        WXComponent parent;
+        if (component == null || (parent = component.getParent()) == null) {
+            return null;
+        }
+        return findCell(parent);
+    }
+
+    private void setAppearanceWatch(WXComponent component, int event, boolean enable) {
+        if(cellDataManager.listData == null
+                || mAppearHelpers == null
+                || TextUtils.isEmpty(component.getRef())){
+            return;
+        }
+        WXCell cell = findCell(component);
+        int type = getCellTemplateItemType(cell);
+        if(type < 0){
+            return;
+        }
+        List<AppearanceHelper>  mAppearListeners = mAppearHelpers.get(type);
+        if(mAppearListeners == null){
+            mAppearListeners = new ArrayList<>();
+            mAppearHelpers.put(type, mAppearListeners);
+        }
+        AppearanceHelper item = null;
+        for(AppearanceHelper mAppearListener : mAppearListeners){
+            if(component.getRef().equals(mAppearListener.getAwareChild().getRef())){
+                item = mAppearListener;
+                break;
+            }
+        }
+        if (item != null) {
+            item.setWatchEvent(event, enable);
+        }else {
+            item = new AppearanceHelper(component,  type);
+            item.setWatchEvent(event, enable);
+            mAppearListeners.add(item);
+        }
+    }
+
+    @Override
+    public void bindAppearEvent(WXComponent component) {
+        setAppearanceWatch(component, AppearanceHelper.APPEAR, true);
+        if(mAppearChangeRunnable == null){
+            mAppearChangeRunnable =  new Runnable() {
+                @Override
+                public void run() {
+                    if(mAppearChangeRunnable != null) {
+                        notifyAppearStateChange(0, 0, 0, 0);
+                    }
+                }
+            };
+        }
+        if (getHostView() != null) {
+            getHostView().removeCallbacks(mAppearChangeRunnable);
+            getHostView().postDelayed(mAppearChangeRunnable, APPEAR_CHANGE_RUNNABLE_DELAY);
+        }
+    }
+
+    @Override
+    public void bindDisappearEvent(WXComponent component) {
+        setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, true);
+        if(mAppearChangeRunnable == null){
+            mAppearChangeRunnable =  new Runnable() {
+                @Override
+                public void run() {
+                    if(mAppearChangeRunnable != null) {
+                        notifyAppearStateChange(0, 0, 0, 0);
+                    }
+                }
+            };
+        }
+        if (getHostView() != null) {
+            getHostView().removeCallbacks(mAppearChangeRunnable);
+            getHostView().postDelayed(mAppearChangeRunnable, APPEAR_CHANGE_RUNNABLE_DELAY);
+        }
+    }
+
+    @Override
+    public void unbindAppearEvent(WXComponent component) {
+        setAppearanceWatch(component, AppearanceHelper.APPEAR, false);
+    }
+
+    @Override
+    public void unbindDisappearEvent(WXComponent component) {
+        setAppearanceWatch(component, AppearanceHelper.DISAPPEAR, false);
+    }
+
+
+    @JSMethod(uiThread = true)
+    public void queryElement(String virtualRef, String selector, JSCallback callback){
+        try{
+            String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
+            String listRef = segments[0];
+            int position = Integer.parseInt(segments[1]); // position
+            WXComponent component = TemplateDom.findVirtualComponentByVRef(getInstanceId(), virtualRef);
+            if(component == null){
+                return;
+            }
+            if(getHostView() == null || getHostView().getInnerView() == null){
+                return;
+            }
+            List<WXComponent>  componentList  = new ArrayList<>(4);
+            Selector.queryElementAll(component, selector, componentList);
+            if(componentList.size() > 0){
+                callback.invoke(TemplateDom.toMap(listRef, position, componentList.get(0)));
+            }else{
+                callback.invoke(new HashMap<>(4));
+            }
+        }catch (Exception e){
+            callback.invoke(new HashMap<>(4));
+            WXLogUtils.e(TAG, e);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void queryElementAll(String virtualRef,  String selector, JSCallback callback){
+        List datas = new ArrayList();
+        try{
+            String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
+            String listRef = segments[0];
+            int position = Integer.parseInt(segments[1]); // position
+            WXComponent component = TemplateDom.findVirtualComponentByVRef(getInstanceId(), virtualRef);
+            if(component == null){
+                return;
+            }
+            if(getHostView() == null || getHostView().getInnerView() == null){
+                return;
+            }
+            List<WXComponent>  componentList  = new ArrayList<>(4);
+            Selector.queryElementAll(component, selector, componentList);
+            for(WXComponent child : componentList){
+                datas.add(TemplateDom.toMap(listRef, position, child));
+            }
+            callback.invoke(datas);
+        }catch (Exception e){
+            callback.invoke(datas);
+            WXLogUtils.e(TAG, e);
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void closest(String virtualRef,  String selector, JSCallback callback){
+        try{
+            String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
+            String listRef = segments[0];
+            int position = Integer.parseInt(segments[1]); // position
+            WXComponent component = TemplateDom.findVirtualComponentByVRef(getInstanceId(), virtualRef);
+            if(component == null){
+                return;
+            }
+            if(getHostView() == null || getHostView().getInnerView() == null){
+                return;
+            }
+            List<WXComponent>  componentList  = new ArrayList<>(4);
+            Selector.closest(component, selector, componentList);
+            if(componentList.size() > 0){
+                callback.invoke(TemplateDom.toMap(listRef, position, componentList.get(0)));
+            }else{
+                callback.invoke(new HashMap<>(4));
+            }
+        }catch (Exception e){
+            callback.invoke(new HashMap<>(4));
+            WXLogUtils.e(TAG, e);
+        }
+    }
+
+
+
+    @JSMethod(uiThread = true)
+    public void scrollToElement(String virtualRef, Map<String, Object> options){
+        scrollTo(virtualRef, options);
+    }
+
+
+    @JSMethod(uiThread = true)
+    public void scrollTo(String virtualRef, Map<String, Object> options){
+        int position = -1;
+        try{
+            if(virtualRef.indexOf(TemplateDom.SEPARATOR) > 0){
+                String[]  segments = virtualRef.split(TemplateDom.SEPARATOR + "");
+                position = Integer.parseInt(segments[0]);
+            }else{
+                position = (int) Float.parseFloat(virtualRef);
+            }
+            if (position >= 0) {
+                boolean smooth = true;
+                float offsetFloat = 0;
+                if(options != null) {
+                    smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
+                    String offsetStr = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
+                    smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
+                    if (offsetStr != null) {
+                        try {
+                            offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offsetStr), getInstance().getInstanceViewPortWidth());
+                        }catch (Exception e ){
+                            WXLogUtils.e("Float parseFloat error :"+e.getMessage());
+                        }
+                    }
+                }
+                final int offset = (int) offsetFloat;
+
+                final int pos = position;
+                BounceRecyclerView bounceRecyclerView = getHostView();
+                if (bounceRecyclerView == null) {
+                    return;
+                }
+                final WXRecyclerView view = bounceRecyclerView.getInnerView();
+                view.scrollTo(smooth, pos, offset, getOrientation());
+            }
+        }catch (Exception e){
+            WXLogUtils.e(TAG, e);
+        }
+    }
+
+
+    @Override
+    public void scrollTo(WXComponent component, Map<String, Object> options) {
+        float offsetFloat = 0;
+        boolean smooth = true;
+        int position = -1;
+        int typeIndex = -1;
+        if (options != null) {
+            String offsetStr = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString();
+            smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true);
+            if (offsetStr != null) {
+                try {
+                    offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offsetStr), getInstance().getInstanceViewPortWidth());
+                }catch (Exception e ){
+                    WXLogUtils.e("Float parseFloat error :"+e.getMessage());
+                }
+            }
+            position = WXUtils.getNumberInt(options.get(Constants.Name.Recycler.CELL_INDEX), -1);
+            typeIndex = WXUtils.getNumberInt(options.get(Constants.Name.Recycler.TYPE_INDEX), -1);
+        }
+        WXCell cell = findCell(component);
+        if(typeIndex >= 0){
+            if(cellDataManager.listData != null && component.getRef() != null){
+                int typePosition = 0;
+                for(int i = 0; i< cellDataManager.listData.size(); i++){
+                    WXCell template = getSourceTemplate(i);
+                    if(template == null){
+                        continue;
+                    }
+                    if(cell.getRef().equals(template.getRef())){
+                        typePosition ++;
+                    }
+                    if(typePosition > typeIndex){
+                        position = i;
+                        break;
+                    }
+                }
+                if(position < 0){
+                    position = cellDataManager.listData.size() - 1;
+                }
+            }
+        }
+
+        final int offset = (int) offsetFloat;
+        BounceRecyclerView bounceRecyclerView = getHostView();
+        if (bounceRecyclerView == null) {
+            return;
+        }
+        if (position >= 0) {
+            final int pos = position;
+            final WXRecyclerView view = bounceRecyclerView.getInnerView();
+            view.scrollTo(smooth, pos, offset, getOrientation());
+        }
+    }
+
+    @Override
+    public int getScrollY() {
+        BounceRecyclerView bounceRecyclerView = getHostView();
+        return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollY();
+    }
+
+    @Override
+    public int getScrollX() {
+        BounceRecyclerView bounceRecyclerView = getHostView();
+        return bounceRecyclerView == null ? 0 : bounceRecyclerView.getInnerView().getScrollX();
+    }
+
+    public int getOrientation() {
+        return orientation;
+    }
+
+    @Override
+    public boolean isScrollable() {
+        return isScrollable;
+    }
+
+
+
+    @Override
+    public void addChild(WXComponent child) {
+        this.addChild(child, -1);
+    }
+
+    @Override
+    protected int getChildrenLayoutTopOffset() {
+        return 0;
+    }
+
+    @Override
+    public void addChild(WXComponent child, int index) {
+        /**
+         *  dom object in component is not tree, build tree
+         * */
+        if(!(child instanceof WXCell)) {
+            super.addChild(child, index);
+        }
+        if(child instanceof WXBaseRefresh){
+            return;
+        }
+        if(child instanceof WXCell){
+            if(child.getAttrs() != null){
+                Object templateId = child.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
+                String key = WXUtils.getString(templateId, null);
+                if(getAttrs().containsKey(Constants.Name.Recycler.LIST_DATA_TEMPLATE_SWITCH_KEY)){
+                    if(defaultTemplateCell == null){
+                        defaultTemplateCell = (WXCell) child;
+                        if(!TextUtils.isEmpty(key)){
+                            defaultTemplateKey = key;
+                        }else{
+                            key = defaultTemplateKey;
+                            child.getAttrs().put(Constants.Name.Recycler.SLOT_TEMPLATE_CASE, key);
+                        }
+                    }
+                }else{
+                    if(defaultTemplateCell == null
+                            || child.getAttrs().containsKey(Constants.Name.Recycler.SLOT_TEMPLATE_DEFAULT)){
+                        defaultTemplateCell = (WXCell) child;
+                        if(!TextUtils.isEmpty(key)){
+                            defaultTemplateKey = key;
+                        }else{
+                            key = defaultTemplateKey;
+                            child.getAttrs().put(Constants.Name.Recycler.SLOT_TEMPLATE_CASE, key);
+                        }
+                    }
+                }
+                if(key != null){
+                    // TODO
+//                    if(child.getDomObject() instanceof  WXCellDomObject
+//                            && getDomObject() instanceof  WXRecyclerDomObject){
+//                        WXCellDomObject domObject = (WXCellDomObject) child.getDomObject();
+//                        domObject.setRecyclerDomObject((WXRecyclerDomObject) getDomObject());
+//                    }
+                    mTemplateSources.put(key, (WXCell) child);
+                    if(mTemplateViewTypes.get(key) == null){
+                        mTemplateViewTypes.put(key, mTemplateViewTypes.size());
+                    }
+                }
+            }
+
+            ((WXCell) child).setCellAppendTreeListener(new WXCell.CellAppendTreeListener() {
+                @Override
+                public void onAppendTreeDone() {
+                    checkAppendDone(false);
+                }
+            });
+        }
+    }
+
+
+    /**
+     * check all the cell has append tree done, then show list
+     * */
+    private void  checkAppendDone(boolean listDone){
+        if(mTemplateSources.size() == 0){
+            return;
+        }
+        Set<Map.Entry<String,WXCell>> cells = mTemplateSources.entrySet();
+        for(Map.Entry<String,WXCell> entry : cells){
+            if(!entry.getValue().isAppendTreeDone()){
+                return;
+            }
+        }
+        hasAppendTreeDone = true;
+        if(hasLayoutDone) {
+            notifyUpdateList();
+        }
+    }
+
+    @Override
+    protected void setHostLayoutParams(BounceRecyclerView host, int width, int height, int left, int right, int top, int bottom) {
+        super.setHostLayoutParams(host, width, height, left, right, top, bottom);
+        if(!hasLayoutDone){
+            hasLayoutDone = true;
+            hasAppendTreeDone = true;
+            notifyUpdateList();
+        }
+    }
+
+
+    /**
+     * RecyclerView manage its children in a way that different from {@link WXVContainer}. Therefore,
+     * {@link WXVContainer#addSubView(View, int)} is an empty implementation in {@link
+     * WXRecyclerView}
+     */
+    @Override
+    public void addSubView(View child, int index) {
+
+    }
+
+
+    /**
+     * all child is template, none need onCreate child except loading and refresh.
+     * */
+    @Override
+    public void createChildViewAt(int index) {
+        int indexToCreate = index;
+        if (indexToCreate < 0) {
+            indexToCreate = childCount() - 1;
+            if (indexToCreate < 0) {
+                return;
+            }
+        }
+        final WXComponent child = getChild(indexToCreate);
+        if (child instanceof WXBaseRefresh) {
+            child.createView();
+            setRefreshOrLoading(child);
+        }
+    }
+
+    @Override
+    public void remove(WXComponent child, boolean destroy) {
+        removeFooterOrHeader(child);
+        super.remove(child, destroy);
+    }
+
+
+
+    @Override
+    public void computeVisiblePointInViewCoordinate(PointF pointF) {
+        RecyclerView view = getHostView().getInnerView();
+        pointF.set(view.computeHorizontalScrollOffset(), view.computeVerticalScrollOffset());
+    }
+
+    @Override
+    protected boolean setProperty(String key, Object param) {
+        switch (key) {
+            case Constants.Name.Recycler.LIST_DATA:{
+                     setListData(param);
+                }
+                return true;
+            case Constants.Name.Recycler.LIST_DATA_ITEM:
+                listDataItemKey = WXUtils.getString(param, listDataItemKey);
+                return true;
+            case Constants.Name.Recycler.LIST_DATA_ITEM_INDEX:
+                listDataIndexKey = WXUtils.getString(param, listDataIndexKey);
+                return true;
+            case Constants.Name.Recycler.LIST_DATA_TEMPLATE_SWITCH_KEY:
+            case Constants.Name.Recycler.SLOT_TEMPLATE_CASE:
+                listDataTemplateKey = WXUtils.getString(param, Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
+                return true;
+            case Name.LOADMOREOFFSET:
+                return true;
+            case Constants.Name.SCROLLABLE:
+                boolean scrollable = WXUtils.getBoolean(param, true);
+                setScrollable(scrollable);
+                return true;
+            case Constants.Name.SCROLL_DIRECTION:
+                if(param != null) {
+                    setScrollDirection(param.toString());
+                }
+                return true;
+            case Constants.Name.SHOW_SCROLLBAR:
+                Boolean result = WXUtils.getBoolean(param,null);
+                if (result != null)
+                    setShowScrollbar(result);
+                return true;
+            case NAME_ITEM_VIEW_CACHE_SIZE:
+                return true;
+            case NAME_HAS_FIXED_SIZE:
+                return true;
+            case Constants.Name.OFFSET_ACCURACY:
+                int accuracy = WXUtils.getInteger(param, 10);
+                setOffsetAccuracy(accuracy);
+                return true;
+        }
+        return super.setProperty(key, param);
+    }
+
+
+    @WXComponentProp(name = Constants.Name.OFFSET_ACCURACY)
+    public void setOffsetAccuracy(int accuracy) {
+        float real = WXViewUtils.getRealPxByWidth(accuracy, getInstance().getInstanceViewPortWidth());
+        this.mOffsetAccuracy = (int) real;
+    }
+
+
+    private void updateRecyclerAttr(){
+        mLayoutType = getAttrs().getLayoutType();
+        mColumnCount = getAttrs().getColumnCount();
+        if (mColumnCount <= 0 && mLayoutType != WXRecyclerView.TYPE_LINEAR_LAYOUT) {
+            Map<String, String> ext = new ArrayMap<>();
+            ext.put("componentType", getComponentType());
+            ext.put("attribute", getAttrs().toString());
+            ext.put("stackTrace", Arrays.toString(Thread.currentThread().getStackTrace()));
+            WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),
+                WXErrorCode.WX_RENDER_ERR_LIST_INVALID_COLUMN_COUNT, "columnCount",
+                String.format(Locale.ENGLISH,
+                    "You are trying to set the list/recycler/vlist/waterfall's column to %d, which is illegal. The column count should be a positive integer",
+                    mColumnCount),
+                ext);
+            mColumnCount = Constants.Value.COLUMN_COUNT_NORMAL;
+        }
+        mColumnGap = getAttrs().getColumnGap();
+        mColumnWidth = getAttrs().getColumnWidth();
+        mPaddingLeft = getPadding().get(CSSShorthand.EDGE.LEFT);
+        mPaddingRight = getPadding().get(CSSShorthand.EDGE.RIGHT);
+
+    }
+
+
+    @WXComponentProp(name = Constants.Name.SCROLL_DIRECTION)
+    public void setScrollDirection(String direction){
+        if(orientation != getAttrs().getOrientation()) {
+            orientation = getAttrs().getOrientation();
+            updateRecyclerAttr();
+            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+            wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap, getOrientation());
+
+        }
+    }
+
+    @WXComponentProp(name = Constants.Name.COLUMN_WIDTH)
+    public void setColumnWidth(int columnCount)  {
+        if(getAttrs().getColumnWidth() != mColumnWidth){
+            updateRecyclerAttr();
+            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+            wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap, getOrientation());
+        }
+    }
+
+    @WXComponentProp(name = Constants.Name.SHOW_SCROLLBAR)
+    public void setShowScrollbar(boolean show) {
+        if(getHostView() == null || getHostView().getInnerView() == null){
+            return;
+        }
+        if (getOrientation() == Constants.Orientation.VERTICAL) {
+            getHostView().getInnerView().setVerticalScrollBarEnabled(show);
+        } else {
+            getHostView().getInnerView().setHorizontalScrollBarEnabled(show);
+        }
+    }
+
+    @WXComponentProp(name = Constants.Name.COLUMN_COUNT)
+    public void setColumnCount(int columnCount){
+        if(getAttrs().getColumnCount() != mColumnCount){
+            updateRecyclerAttr();
+            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+            wxRecyclerView.initView(getContext(), mLayoutType,mColumnCount,mColumnGap,getOrientation());
+        }
+    }
+
+    @WXComponentProp(name = Constants.Name.COLUMN_GAP)
+    public void setColumnGap(float columnGap) throws InterruptedException {
+        if(getAttrs().getColumnGap() != mColumnGap) {
+            updateRecyclerAttr();
+            WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+            wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
+        }
+    }
+
+    @WXComponentProp(name = Constants.Name.SCROLLABLE)
+    public void setScrollable(boolean scrollable) {
+        WXRecyclerView inner = getHostView().getInnerView();
+        inner.setScrollable(scrollable);
+    }
+
+    @JSMethod
+    public void setListData(Object param){
+        param = parseListDataToJSONArray(param);
+        boolean update = cellDataManager.listData != param;
+        if(param instanceof  JSONArray){
+            if(update){
+                cellDataManager.setListData((JSONArray) param);
+                notifyUpdateList();
+            }
+        }
+    }
+
+    @JSMethod
+    public void  appendData(JSONArray data){
+        if(data == null || data.size() == 0){
+            return;
+        }
+        if(cellDataManager.listData == null){
+            cellDataManager.listData = new JSONArray();
+        }
+        int position = cellDataManager.listData.size();
+        if(position < 0){
+            position = 0;
+        }
+        if(data instanceof  JSONArray){
+            cellDataManager.listData.addAll(data);
+        }
+        getHostView().getRecyclerViewBaseAdapter().notifyItemRangeInserted(position, data.size());
+    }
+
+    @JSMethod
+    public void  insertData(int index, Object data){
+        if(data == null){
+            return;
+        }
+
+        if(cellDataManager.listData == null || index > cellDataManager.listData.size()){
+            return;
+        }
+        boolean renderStateChanged = cellDataManager.insertData(index, data);
+        if(renderStateChanged){
+            notifyUpdateList();
+        }else{
+            getHostView().getRecyclerViewBaseAdapter().notifyItemInserted(index);
+        }
+    }
+
+    @JSMethod
+    public void  appendRange(int index, JSONArray data){
+         insertRange(index, data);
+    }
+
+
+    /**
+     * when update data, list maybe contains sticky, may use position, when position changed should be rendered
+     * so use notifyUpdateList is better
+     * */
+
+    @JSMethod
+    public void  insertRange(int index, JSONArray data){
+        if(data == null || data.size() == 0){
+            return;
+        }
+        if(cellDataManager.listData == null || index > cellDataManager.listData.size()){
+            return;
+        }
+        boolean renderStateChange = cellDataManager.insertRange(index, data);
+        if(renderStateChange){
+            notifyUpdateList();
+        }else{
+            getHostView().getRecyclerViewBaseAdapter().notifyItemRangeInserted(index, data.size());
+        }
+
+    }
+
+    @JSMethod
+    public void  updateData(int index, Object data){
+        if(data == null){
+            return;
+        }
+        if(cellDataManager.listData == null || index >= cellDataManager.listData.size()){
+            return;
+        }
+        boolean onlyDataChange = cellDataManager.updateData(data, index);
+        if(onlyDataChange) {
+            getHostView().getRecyclerViewBaseAdapter().notifyItemChanged(index, data);
+        }else{
+            notifyUpdateList();
+        }
+    }
+
+    @JSMethod
+    public void  removeData(int index, int count){
+        if(cellDataManager.listData == null
+                || index >= cellDataManager.listData.size()){
+            return;
+        }
+        if(count <= 0){
+            count = 1;
+        }
+        int removeCount = 0;
+        while (count > 0 && index < cellDataManager.listData.size()){
+            cellDataManager.removeData(index);
+            count--;
+            removeCount++;
+        }
+        if(removeCount > 0) {
+            notifyUpdateList();
+        }
+    }
+
+
+    @JSMethod
+    public void resetLoadmore() {
+        mForceLoadmoreNextTime = true;
+        mListCellCount = 0;
+    }
+
+
+    @Override
+    public void updateProperties(Map<String, Object> props) {
+        super.updateProperties(props);
+        if(props.containsKey(Constants.Name.PADDING)
+                || props.containsKey(Constants.Name.PADDING_LEFT)
+                || props.containsKey(Constants.Name.PADDING_RIGHT)){
+
+            if(mPaddingLeft != getPadding().get(CSSShorthand.EDGE.LEFT)
+                    || mPaddingRight != getPadding().get(CSSShorthand.EDGE.RIGHT)) {
+                updateRecyclerAttr();
+                WXRecyclerView wxRecyclerView = getHostView().getInnerView();
+                wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
+            }
+        }
+    }
+
+
+
+    @Override
+    public void addEvent(String type) {
+        super.addEvent(type);
+        if (ScrollStartEndHelper.isScrollEvent(type)
+                && getHostView() != null
+                && getHostView().getInnerView() != null
+                && !mHasAddScrollEvent) {
+            mHasAddScrollEvent = true;
+            WXRecyclerView innerView = getHostView().getInnerView();
+            innerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+                private int offsetXCorrection, offsetYCorrection;
+                private boolean mFirstEvent = true;
+
+                @Override
+                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                    super.onScrolled(recyclerView, dx, dy);
+                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+                    if (!layoutManager.canScrollVertically()) {
+                        return;
+                    }
+                    int offsetX = recyclerView.computeHorizontalScrollOffset();
+                    int offsetY = recyclerView.computeVerticalScrollOffset();
+
+                    if (dx == 0 && dy == 0) {
+                        offsetXCorrection = offsetX;
+                        offsetYCorrection = offsetY;
+                        offsetX = 0;
+                        offsetY = 0;
+                    } else {
+                        offsetX = offsetX - offsetXCorrection;
+                        offsetY = offsetY - offsetYCorrection;
+                    }
+                    getScrollStartEndHelper().onScrolled(offsetX, offsetY);
+                    if(!getEvents().contains(Constants.Event.SCROLL)){
+                        return;
+                    }
+                    if (mFirstEvent) {
+                        //skip first event
+                        mFirstEvent = false;
+                        return;
+                    }
+
+                    if (shouldReport(offsetX, offsetY)) {
+                        fireScrollEvent(recyclerView, offsetX, offsetY);
+                    }
+                }
+            });
+        }
+    }
+
+    private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY) {
+        fireEvent(Constants.Event.SCROLL, getScrollEvent(recyclerView, offsetX, offsetY));
+    }
+
+    public Map<String, Object> getScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY){
+        offsetY = -calcContentOffset(recyclerView);
+        int contentWidth = recyclerView.getMeasuredWidth() + recyclerView.computeHorizontalScrollRange();
+        int contentHeight = calcContentSize();
+
+        Map<String, Object> event = new HashMap<>(3);
+        Map<String, Object> contentSize = new HashMap<>(3);
+        Map<String, Object> contentOffset = new HashMap<>(3);
+
+        contentSize.put(Constants.Name.WIDTH, WXViewUtils.getWebPxByWidth(contentWidth, getInstance().getInstanceViewPortWidth()));
+        contentSize.put(Constants.Name.HEIGHT, WXViewUtils.getWebPxByWidth(contentHeight, getInstance().getInstanceViewPortWidth()));
+
+        contentOffset.put(Constants.Name.X, - WXViewUtils.getWebPxByWidth(offsetX, getInstance().getInstanceViewPortWidth()));
+        contentOffset.put(Constants.Name.Y, - WXViewUtils.getWebPxByWidth(offsetY, getInstance().getInstanceViewPortWidth()));
+        event.put(Constants.Name.CONTENT_SIZE, contentSize);
+        event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
+        event.put(Constants.Name.ISDRAGGING, recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING);
+        return event;
+    }
+
+
+
+    private boolean shouldReport(int offsetX, int offsetY) {
+        if (mLastReport.x == -1 && mLastReport.y == -1) {
+            mLastReport.x = offsetX;
+            mLastReport.y = offsetY;
+            return true;
+        }
+
+        int gapX = Math.abs(mLastReport.x - offsetX);
+        int gapY = Math.abs(mLastReport.y - offsetY);
+
+        if (gapX >= mOffsetAccuracy || gapY >= mOffsetAccuracy) {
+            mLastReport.x = offsetX;
+            mLastReport.y = offsetY;
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Setting refresh view and loading view
+     *
+     * @param child the refresh_view or loading_view
+     */
+    private boolean setRefreshOrLoading(final WXComponent child) {
+        if (child instanceof WXRefresh && getHostView() != null) {
+            getHostView().setOnRefreshListener((WXRefresh) child);
+            getHostView().postDelayed(WXThread.secure(new Runnable() {
+                @Override
+                public void run() {
+                    getHostView().setHeaderView(child);
+                }
+            }), 100);
+            return true;
+        }
+
+        if (child instanceof WXLoading && getHostView() != null) {
+            getHostView().setOnLoadingListener((WXLoading) child);
+            getHostView().postDelayed(WXThread.secure(new Runnable() {
+                @Override
+                public void run() {
+                    getHostView().setFooterView(child);
+                }
+            }), 100);
+            return true;
+        }
+        return false;
+    }
+
+
+    private void removeFooterOrHeader(WXComponent child) {
+        if (child instanceof WXLoading) {
+            getHostView().removeFooterView(child);
+        } else if (child instanceof WXRefresh) {
+            getHostView().removeHeaderView(child);
+        }
+    }
+
+    @Override
+    public ViewGroup.LayoutParams getChildLayoutParams(WXComponent child, View hostView, int width, int height, int left, int right, int top, int bottom) {
+        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) hostView.getLayoutParams();
+        if (child instanceof WXBaseRefresh && params == null) {
+            params = new LinearLayout.LayoutParams(width, height);
+        } else if (params == null) {
+            params = new RecyclerView.LayoutParams(width, height);
+        } else {
+            params.width = width;
+            params.height = height;
+
+            this.setMarginsSupportRTL(params, left, 0, right, 0);
+        }
+        return params;
+    }
+
+
+    @Override
+    public void destroy() {
+        synchronized (this){
+            if(getHostView() != null){
+                if(mAppearChangeRunnable != null) {
+                    getHostView().removeCallbacks(mAppearChangeRunnable);
+                    mAppearChangeRunnable = null;
+                }
+                getHostView().removeCallbacks(listUpdateRunnable);
+                if(getHostView().getInnerView() != null){
+                    getHostView().getInnerView().setAdapter(null);
+                }
+            }
+            if(cellDataManager.listData != null){
+                cellDataManager.setListData(null);
+            }
+            if(mStickyHelper != null){
+                mStickyHelper = null;
+            }
+            if(mTemplateViewTypes != null){
+                mTemplateViewTypes.clear();
+            }
+            if(mTemplateSources != null){
+                mTemplateSources.clear();
+            }
+            if(mAppearHelpers != null){
+                mAppearHelpers.clear();
+            }
+            if(mDisAppearWatchList != null){
+                mDisAppearWatchList.clear();
+            }
+            super.destroy();
+        }
+    }
+
+
+
+    @Override
+    public void onViewRecycled(TemplateViewHolder holder) {}
+
+    @Override
+    public void onBindViewHolder(final TemplateViewHolder templateViewHolder, int position) {
+        if(templateViewHolder == null){
+            return;
+        }
+        WXCell component = templateViewHolder.getTemplate();
+        if(component == null){
+            return;
+        }
+        if(templateViewHolder.getHolderPosition() >= 0){
+            fireEvent(TemplateDom.DETACH_CELL_SLOT, TemplateDom.findAllComponentRefs(getRef(), position, component));
+        }
+        long start = System.currentTimeMillis();
+        templateViewHolder.setHolderPosition(position);
+        Object data = cellDataManager.listData.get(position);
+        CellRenderState cellRenderState = cellDataManager.getRenderState(position);
+        if((component.getRenderData() == data && (cellRenderState == null || !cellRenderState.isDirty()))){
+            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
+                WXLogUtils.d(TAG,  position + " position "+ getTemplateKey(position) + " onBindViewHolder none data update "
+                        + " component " + component.hashCode());
+            }
+            fireEvent(TemplateDom.ATTACH_CELL_SLOT, TemplateDom.findAllComponentRefs(getRef(), position, component));
+            return;  //none update just return
+        }else{
+            List<WXComponent> updates = doRenderTemplate(component, position);
+            Statements.doInitCompontent(updates);
+            component.setRenderData(data);
+            Layouts.doLayoutAsync(templateViewHolder, true);
+            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG){
+                WXLogUtils.d(TAG,  position + " position "+ getTemplateKey(position) + " onBindViewHolder used " + (System.currentTimeMillis() - start)
+                  + " component " + component.hashCode());
+            }
+        }
+    }
+
+    @Override
+    public TemplateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        String template = mTemplateViewTypes.keyAt(viewType);
+        WXCell source = mTemplateSources.get(template);
+        if(source == null){
+            FrameLayout view = new FrameLayout(getContext());
+            view.setLayoutParams(new FrameLayout.LayoutParams(0, 0));
+            return new TemplateViewHolder(this, view, viewType);
+        }
+        WXCell component =  getCellTemplateFromCache(template);
+        boolean cacheHit = true;
+        if(component == null){
+            cacheHit = false;
+            if(!source.isSourceUsed()){
+                source.setSourceUsed(true);
+                renderTemplateCellWithData(source);
+                component = source;
+                if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
+                    WXLogUtils.d(TAG, template + " onCreateViewHolder source");
+                }
+            }
+        }
+        if(component == null) {
+            long start = System.currentTimeMillis();
+            component = (WXCell) copyComponentFromSourceCell(source);
+            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
+                WXLogUtils.d(TAG, template + " onCreateViewHolder copy used " + (System.currentTimeMillis() - start));
+            }
+        }
+        if(component.isLazy() || component.getHostView() == null) {
+            doCreateCellViewBindData(component, template, false);
+            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
+                WXLogUtils.d(TAG, template + " onCreateViewHolder  cache hit " + cacheHit   + " view not idle init");
+            }
+        }else{
+            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
+                WXLogUtils.d(TAG, template + " onCreateViewHolder  cache hit " + cacheHit + " view idle init " + component.hashCode()
+                 + "  " + source.hashCode());
+            }
+        }
+        TemplateViewHolder templateViewHolder = new TemplateViewHolder(this, component, viewType);
+        return  templateViewHolder;
+    }
+
+
+
+    /**
+     * @param position
+     * when template not send, return an invalid id, use empty view holder.
+     * when template has sended, use real template id to refresh view, use real view holder.
+     * */
+    @Override
+    public int getItemViewType(int position) {
+        String template = getTemplateKey(position);
+        int type =  mTemplateViewTypes.indexOfKey(template);
+        if(type < 0){
+            type = mTemplateViewTypes.indexOfKey(EMPTY_HOLDER_TEMPLATE_KEY);
+        }
+        return type;
+    }
+
+
+    /**
+     * create code context for render component and do render
+     * */
+    private List<WXComponent> doRenderTemplate(WXCell cell, int position){
+        this.cellRenderContext.clear();
+        Object item = cellDataManager.listData.get(position);
+        CellRenderState cellRenderState = cellDataManager.getRenderState(position);
+        cellRenderContext.renderState = cellRenderState;
+        cellRenderContext.templateList = this;
+        cellRenderContext.position = position;
+
+        ArrayStack stack = cellRenderContext.stack;
+        Map map = cellRenderContext.map;
+        if(cellDataManager.listData != null){
+            stack.push(map);
+            map.put(listDataKey, cellDataManager.listData);
+            if(!TextUtils.isEmpty(listDataIndexKey)) {
+                map.put(listDataIndexKey, new PositionRef(cellRenderState));
+            }
+            if(!TextUtils.isEmpty(listDataItemKey)) {
+                map.put(listDataItemKey, item);
+            }else{
+                stack.push(item);
+            }
+        }
+        if(cellRenderState.itemId <= 0){
+            getItemId(position);
+        }
+        List<WXComponent> updates = Statements.doRender(cell, this.cellRenderContext);
+        if(cellRenderState.isDirty()){
+            cellRenderState.resetDirty();
+        }
+        return  updates;
+    }
+
+    public ArrayStack copyStack(CellRenderContext context, ArrayStack stack){
+        ArrayStack onceStack = new ArrayStack();
+        for(int index=0;  index <  stack.size(); index++) {
+            Object value = stack.get(index);
+            if(value instanceof  Map){
+                value  = new HashMap((Map) value);
+            }
+            onceStack.push(value);
+        }
+        return onceStack;
+    }
+
+
+    /**
+     * return tepmlate key for position
+     * */
+    public String getTemplateKey(int position){
+        Object data =  safeGetListData(position);
+        return getTemplateKey(data);
+    }
+
+    /**
+     * return template key for position never be null
+     * */
+    public String getTemplateKey(Object data){
+        String template = null;
+        if(data instanceof  JSONObject) {
+            template = ((JSONObject)data).getString(listDataTemplateKey);
+        }
+        if(TextUtils.isEmpty(template)){
+            if(defaultTemplateCell != null){
+                template  = defaultTemplateKey;
+            }else {
+                template = "";
+            }
+        }
+        return  template;
+    }
+
+    /**
+     * get source template
+     * */
+    public WXCell getSourceTemplate(int position){
+        String template = getTemplateKey(position);
+        return mTemplateSources.get(template);
+    }
+
+
+
+    /**
+     * get template key from cell; -1 for  cann't find  type
+     * */
+    private int getCellTemplateItemType(WXCell cell){
+        if(cell == null){
+            return  -1;
+        }
+        if(cell.getAttrs() != null){
+            Object templateId = cell.getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE);
+            String template = WXUtils.getString(templateId, null);
+            if(cell == defaultTemplateCell){
+                template = defaultTemplateKey;
+            }
+            int type =  mTemplateViewTypes.indexOfKey(template);
+            if(type < 0){
+                return -1;
+            }
+            return  type;
+        }
+        return  0;
+    }
+
+    @Override
+    public int getItemCount() {
+        if(!hasLayoutDone){
+            return 0;
+        }
+        if(!hasAppendTreeDone){
+            return 0;
+        }
+        if(cellDataManager.listData == null){
+            return  0;
+        }
+        if(mTemplateViewTypes == null || mTemplateViewTypes.size() <= 1){
+            return 0;
+        }
+        if(mTemplateSources == null || mTemplateSources.size() == 0){
+            return  0;
+        }
+        return cellDataManager.listData.size();
+    }
+
+    @Override
+    public boolean onFailedToRecycleView(TemplateViewHolder holder) {
+        return false;
+    }
+
+
+    /**
+     * @param position
+     * when template not send by javascript, return an invalid id, force  use empty view holder.
+     * when template has sended by javascript, use real template id to refresh view, use real view holder.
+     * */
+    @Override
+    public long getItemId(int position) {
+        CellRenderState renderState = cellDataManager.getRenderState(position);
+        if(renderState.itemId <=  0){
+            String template = getTemplateKey(position);
+            if(TextUtils.isEmpty(template)){
+                return RecyclerView.NO_ID;
+            }
+            Object data = safeGetListData(position);
+            if(data instanceof  JSONObject && ((JSONObject)data).containsKey("keyItemId")){
+                renderState.itemId =  ((JSONObject)data).getLongValue("keyItemId");
+            }else{
+                long id = Math.abs(data.hashCode());
+                long itemId = (id<< 24) + position;
+                renderState.itemId = itemId;
+            }
+        }
+        return renderState.itemId;
+    }
+
+    @Override
+    public void onBeforeScroll(int dx, int dy) {
+        if(mStickyHelper != null){
+            mStickyHelper.onBeforeScroll(dx, dy);
+        }
+    }
+
+    @Override
+    public void onLoadMore(int offScreenY) {
+        try {
+            String offset = getAttrs().getLoadMoreOffset();
+
+            if (TextUtils.isEmpty(offset)) {
+                offset = "0";
+            }
+            float offsetParsed = WXViewUtils.getRealPxByWidth(Integer.parseInt(offset),getInstance().getInstanceViewPortWidth());
+
+            if (offScreenY <= offsetParsed && cellDataManager.listData != null) {
+                if (mListCellCount != cellDataManager.listData.size()
+                        || mForceLoadmoreNextTime) {
+                    fireEvent(Constants.Event.LOADMORE);
+                    mListCellCount = cellDataManager.listData.size();
+                    mForceLoadmoreNextTime = false;
+                }
+            }
+        } catch (Exception e) {
+            if (WXEnvironment.isApkDebugable()){
+                WXLogUtils.d(TAG + " onLoadMore : ", e);
+            }
+        }
+    }
+
+    /**
+     *
+     * first fire appear event.
+     * */
+    @Override
+    public void notifyAppearStateChange(int firstVisible, int lastVisible, int directionX, int directionY) {
+        if(mAppearHelpers == null
+                || mAppearHelpers.size() <= 0){
+            return;
+        }
+        if(mAppearChangeRunnable != null) {
+            getHostView().removeCallbacks(mAppearChangeRunnable);
+            mAppearChangeRunnable = null;
+        }
+        String direction = directionY > 0 ? Constants.Value.DIRECTION_UP :
+                directionY < 0 ? Constants.Value.DIRECTION_DOWN : null;
+        if (getOrientation() == Constants.Orientation.HORIZONTAL && directionX != 0) {
+            direction = directionX > 0 ? Constants.Value.DIRECTION_LEFT : Constants.Value.DIRECTION_RIGHT;
+        }
+        RecyclerView recyclerView = getHostView().getInnerView();
+        for(int position=firstVisible; position<=lastVisible; position++){
+            int type = getItemViewType(position);
+            List<AppearanceHelper> helpers = mAppearHelpers.get(type);
+            if(helpers == null){
+                continue;
+            }
+            for(AppearanceHelper helper : helpers){
+                if(!helper.isWatch()){
+                    continue;
+                }
+                TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(position);
+                if(itemHolder == null || itemHolder.getComponent() == null){
+                    break;
+                }
+                List<WXComponent> childListeners = findChildListByRef(itemHolder.getComponent(), helper.getAwareChild().getRef());
+                if(childListeners == null || childListeners.size() == 0){
+                    break;
+                }
+
+                Map<String, Map<Integer, List<Object>>> disAppearList = mDisAppearWatchList.get(position);
+                if(disAppearList == null){
+                    disAppearList = new ArrayMap<>();
+                    mDisAppearWatchList.put(position, disAppearList);
+                }
+
+                Map<Integer, List<Object>> componentDisAppearList = disAppearList.get(helper.getAwareChild().getRef());
+                if(componentDisAppearList == null){
+                    componentDisAppearList = new ArrayMap<>();
+                    disAppearList.put(helper.getAwareChild().getRef(), componentDisAppearList);
+                }
+
+                for(int m=0; m<childListeners.size(); m++){
+                    WXComponent childLisener = childListeners.get(m);
+                    if(childLisener.getHostView() == null){
+                        continue;
+                    }
+                    boolean appear = helper.isViewVisible(childLisener.getHostView());
+                    int key = childLisener.getHostView().hashCode();
+                    if(appear){
+                        if(!componentDisAppearList.containsKey(key)){
+                            childLisener.notifyAppearStateChange(Constants.Event.APPEAR, direction);
+                            List<Object> eventArgs = null;
+                            if(childLisener.getEvents() != null
+                                    && childLisener.getEvents().getEventBindingArgsValues() != null
+                                    && childLisener.getEvents().getEventBindingArgsValues().get(Constants.Event.DISAPPEAR) != null){
+                                eventArgs = childLisener.getEvents().getEventBindingArgsValues().get(Constants.Event.DISAPPEAR);
+                            }
+                            componentDisAppearList.put(key, eventArgs);
+                        }
+                    }else{
+                        if(componentDisAppearList.containsKey(key)){
+                            childLisener.notifyAppearStateChange(Constants.Event.DISAPPEAR, direction);
+                            componentDisAppearList.remove(key);
+                        }
+                    }
+                }
+            }
+        }
+
+        //handle disappear event, out of position
+        int count = getItemCount();
+        for (int position=0; position<count; position++){
+            if(position >= firstVisible && position <= lastVisible){
+                position = lastVisible + 1;
+                continue;
+            }
+            Map<String, Map<Integer, List<Object>>> map = mDisAppearWatchList.get(position);
+            if(map == null){
+                continue;
+            }
+            WXCell template = mTemplateSources.get(getTemplateKey(position));
+            if(template == null){
+                return;
+            }
+            Set<Map.Entry<String, Map<Integer, List<Object>>>> cellWatcherEntries = map.entrySet();
+            for(Map.Entry<String,Map<Integer, List<Object>>> cellWatcherEntry : cellWatcherEntries){
+                String ref = cellWatcherEntry.getKey();
+                WXComponent component = findChildByRef(template, ref);
+                if(component == null){
+                    continue;
+                }
+                Map<Integer, List<Object>> eventWatchers = cellWatcherEntry.getValue();
+                if(eventWatchers == null || eventWatchers.size() == 0){
+                    continue;
+                }
+                WXEvent events = component.getEvents();
+                Set<Map.Entry<Integer, List<Object>>> eventWatcherEntries = eventWatchers.entrySet();
+                for(Map.Entry<Integer, List<Object>> eventWatcherEntry : eventWatcherEntries){
+                    events.putEventBindingArgsValue(Constants.Event.DISAPPEAR, eventWatcherEntry.getValue());
+                    component.notifyAppearStateChange(Constants.Event.DISAPPEAR, direction);
+                }
+                eventWatchers.clear();
+            }
+            mDisAppearWatchList.remove(position);
+        }
+    }
+
+
+    private Object safeGetListData(int position){
+        try{
+            return cellDataManager.listData.get(position);
+        }catch (Exception e){return  JSONObject.parseObject("{}");}
+    }
+
+    public void  notifyUpdateList(){
+        if(getHostView() == null
+                || getHostView().getInnerView() == null
+                || listUpdateRunnable == null){
+            return;
+        }
+        if(Looper.getMainLooper().getThread().getId() != Thread.currentThread().getId()){
+            getHostView().removeCallbacks(listUpdateRunnable);
+            getHostView().post(listUpdateRunnable);
+        }else{
+            listUpdateRunnable.run();
+        }
+    }
+
+    private int calcContentSize() {
+        int totalHeight = 0;
+        if(cellDataManager.listData == null){
+            return totalHeight;
+        }
+        for (int i = 0; i < cellDataManager.listData.size(); i++) {
+            WXCell child = getSourceTemplate(i);
+            if (child != null) {
+                totalHeight += child.getLayoutHeight();
+            }
+        }
+        return totalHeight;
+    }
+
+    public int calcContentOffset(RecyclerView recyclerView) {
+        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+        if (layoutManager instanceof LinearLayoutManager) {
+            int firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+            int offset = 0;
+            for (int i=0;i<firstVisibleItemPosition;i++) {
+                WXCell cell = getSourceTemplate(i);
+                if(cell == null){
+                    continue;
+                }
+                offset -= cell.getLayoutHeight();
+            }
+
+            if (layoutManager instanceof GridLayoutManager) {
+                int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
+                offset = offset / spanCount;
+            }
+            View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
+            if(firstVisibleView != null) {
+                offset += firstVisibleView.getTop();
+            }
+            return offset;
+        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+            int spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
+            int firstVisibleItemPosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(null)[0];
+            int offset = 0;
+            for (int i=0;i<firstVisibleItemPosition;i++) {
+                WXCell cell = getSourceTemplate(i);
+                if(cell == null){
+                    continue;
+                }
+                offset -= cell.getLayoutHeight();
+            }
+            offset = offset / spanCount;
+
+            View firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition);
+            if(firstVisibleView != null) {
+                offset += firstVisibleView.getTop();
+            }
+            return offset;
+        }
+        return -1;
+    }
+
+    /**
+     * find certain class type parent
+     * */
+    public WXComponent findParentType(WXComponent component, Class type){
+        if(type.isAssignableFrom(component.getClass())){
+            return component;
+        }
+        if(component.getParent() != null) {
+            findTypeParent(component.getParent(), type);
+        }
+        return  null;
+    }
+
+
+    /**
+     * find child by ref
+     * */
+    public WXComponent findChildByRef(WXComponent component, String ref){
+        if(ref.equals(component.getRef())){
+            return component;
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            for(int i=0; i<container.getChildCount(); i++){
+                WXComponent child = findChildByRef(container.getChild(i), ref);
+                if(child != null){
+                    return  child;
+                }
+            }
+        }
+        return  null;
+    }
+
+    /**
+     * find child list, has same ref
+     * */
+    public List<WXComponent> findChildListByRef(WXComponent component, String ref){
+        WXComponent child = findChildByRef(component, ref);
+        if(child == null){
+            return  null;
+        }
+        List<WXComponent> componentList = new ArrayList<>();
+        WXVContainer container = child.getParent();
+        if(container != null && (!(container instanceof WXRecyclerTemplateList))){
+            for(int i=0; i<container.getChildCount(); i++){
+                WXComponent element = container.getChild(i);
+                if(ref.equals(element.getRef())){
+                    componentList.add(element);
+                }
+            }
+        }else{
+            componentList.add(child);
+        }
+        return  componentList;
+    }
+
+
+
+    /**
+     * find child by ref
+     * */
+    public WXComponent findChildByAttrsRef(WXComponent component, String ref){
+        if(component.getAttrs() != null && ref.equals(component.getAttrs().get(TemplateDom.ATTRS_KEY_REF))){
+            return component;
+        }
+        if(component instanceof WXVContainer){
+            WXVContainer container = (WXVContainer) component;
+            for(int i=0; i<container.getChildCount(); i++){
+                WXComponent child = findChildByAttrsRef(container.getChild(i), ref);
+                if(child != null){
+                    return  child;
+                }
+            }
+        }
+        return  null;
+    }
+
+
+
+    /**
+     * @param  template  template name
+     * get cell template component from cache, if cell component not load
+     * start load cell template
+     * */
+    private WXCell getCellTemplateFromCache(final String template){
+        TemplateCache cache = mTemplatesCache.get(template);
+        WXCell component =  null;
+        if(cache != null && cache.cells != null && cache.cells.size() > 0){
+            component = cache.cells.poll();
+        }
+        if(cache == null ||  !cache.isLoadIng){
+            if(cache == null){
+                cache = new TemplateCache();
+                mTemplatesCache.put(template, cache);
+            }
+            cache.isLoadIng = true;
+            WXCell source = mTemplateSources.get(template);
+            if(source != null){
+                boolean allowPreload = WXUtils.getBoolean(source.getAttrs().get("preload"), true);
+                if(allowPreload) {
+                    AsyncCellLoadTask asyncCellLoadTask = new AsyncCellLoadTask(template, source, this);
+                    asyncCellLoadTask.startTask();
+                }
+            }
+        }
+        return  component;
+    }
+
+    /**
+     * copy cell component from source, init render data, and return source
+     * if none data, return null
+     * */
+    public WXComponent copyComponentFromSourceCell(WXCell cell){
+        renderTemplateCellWithData(cell);
+        WXCell component = (WXCell) Statements.copyComponentTree(cell);
+        return component;
+    }
+
+    /**
+     *  render  init with  cell with one data,
+     *  if template has already render with data, done nothing
+     *  @param  cell
+     * */
+    private synchronized void renderTemplateCellWithData(WXCell cell){
+        if(cell.getRenderData() == null){
+            if(cellDataManager.listData != null && cellDataManager.listData.size() > 0){
+                synchronized (this){
+                    if(cell.getRenderData() == null){
+                        Statements.parseStatementsToken(cell);
+                        for(int i = 0; i< cellDataManager.listData.size(); i++){
+                            if(cell == getSourceTemplate(i)){
+                                Object data = cellDataManager.listData.get(i);
+                                doRenderTemplate(cell, i);
+                                Layouts.doLayoutSync(cell, getLayoutWidth(), getLayoutHeight());
+                                cell.setRenderData(data);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * create view for lazy cell and bind data
+     * */
+    public static void doCreateCellViewBindData(WXCell component, String template, boolean inPreload){
+        if(component.isLazy() || component.getHostView() == null){
+            long start = System.currentTimeMillis();
+            Statements.initLazyComponent(component, null);
+            if(WXEnvironment.isOpenDebugLog() && ENABLE_TRACE_LOG) {
+                WXLogUtils.d(TAG, " doCreateCellViewBindData " + template + " in preload "+ inPreload + " used " + (System.currentTimeMillis() - start));
+            }
+        }
+    }
+
+    public ScrollStartEndHelper getScrollStartEndHelper() {
+        if(mScrollStartEndHelper == null){
+            mScrollStartEndHelper = new ScrollStartEndHelper(this);
+        }
+        return mScrollStartEndHelper;
+    }
+
+    public int getTemplateCacheSize() {
+        return templateCacheSize;
+    }
+
+    public ConcurrentHashMap<String, TemplateCache> getTemplatesCache() {
+        if(mTemplatesCache == null){
+            mTemplatesCache = new ConcurrentHashMap<>();
+        }
+        return mTemplatesCache;
+    }
+
+
+    public CellDataManager getCellDataManager() {
+        return cellDataManager;
+    }
+
+
+    private JSONArray parseListDataToJSONArray(Object value){
+        try{
+            if(value instanceof  JSONArray){
+                return (JSONArray) value;
+            }
+            if(value instanceof String){
+                JSONArray array = JSONArray.parseArray(getAttrs().get(Constants.Name.Recycler.LIST_DATA).toString());
+                return array;
+            }
+        }catch (Exception e){
+            WXLogUtils.e(TAG, "parseListDataException" + e.getMessage());
+        }
+        return new JSONArray();
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java
new file mode 100644
index 0000000..1fdde01
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template.jni;
+
+public class NativeRenderLayoutDirection {
+    public static final int inherit = 0;
+    public static final int ltr = 1;
+    public static final int rtl = 2;
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
new file mode 100644
index 0000000..6031a9f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.list.template.jni;
+
+import org.apache.weex.base.CalledByNative;
+import org.apache.weex.ui.component.WXComponent;
+
+/**
+ * Created by furture on 2018/5/3.
+ */
+
+public class NativeRenderObjectUtils {
+
+
+    /**
+     * getRenderObject
+     * */
+    public static native long nativeGetRenderObject(String instanceId, String ref);
+
+    /**
+     * render object layout
+     * */
+    public static native void nativeUpdateRenderObjectStyle(long ptr, String key, String value);
+    public static native void nativeUpdateRenderObjectAttr(long ptr, String key, String value);
+
+    /**
+     * copy render object
+     * */
+    public static native long nativeCopyRenderObject(long ptr);
+
+    /**
+     * layout render object
+     * */
+    public static native int nativeLayoutRenderObject(long ptr, float width, float height);
+
+    public static native int nativeRenderObjectGetLayoutDirectionFromPathNode(long ptr);
+    /**
+     * get child length
+     * */
+    public static native void nativeAddChildRenderObject(long parent, long child);
+
+    /**
+     * get component, tranverse child and update component
+     * */
+    public static native boolean nativeRenderObjectHasNewLayout(long ptr);
+    public static native int nativeRenderObjectChildCount(long ptr);
+    public static native long nativeRenderObjectGetChild(long ptr, int index);
+    public static native void nativeRenderObjectUpdateComponent(long ptr, WXComponent component);
+    public static native void nativeRenderObjectChildWaste(long ptr, boolean waster);
+
+
+    /**
+     * component size
+     * */
+    @CalledByNative
+    public static void updateComponentSize(WXComponent component, float top, float bottom, float left, float right, float height, float width){
+        component.updateDemission(top, bottom, left, right, height, width);
+        component.applyLayoutOnly();
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/OnActivePseudoListner.java b/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/OnActivePseudoListner.java
new file mode 100644
index 0000000..8585fe6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/OnActivePseudoListner.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.pesudo;
+
+/**
+ * Created by sospartan on 05/01/2017.
+ */
+public interface OnActivePseudoListner {
+  void updateActivePseudo(boolean isSet);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/PesudoStatus.java b/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/PesudoStatus.java
new file mode 100644
index 0000000..0a9af49
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/PesudoStatus.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.pesudo;
+
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+
+import org.apache.weex.common.Constants;
+
+import java.util.Map;
+import org.apache.weex.common.Constants.PSEUDO;
+
+/**
+ * Created by sospartan on 05/01/2017.
+ */
+
+public class PesudoStatus {
+
+  /**
+   * See {@link PSEUDO}
+   */
+  private int[] mStatuses = new int[4];
+
+  private static final int UNSET = 0;
+  private static final int SET = 1;
+
+  static final int CLASS_ACTIVE = 0;
+  static final int CLASS_FOCUS = 1;
+  static final int CLASS_ENABLED = 2;
+  static final int CLASS_DISABLED = 3;
+
+  public PesudoStatus(){
+    for (int i = 0; i < mStatuses.length; i++) {
+        mStatuses[i] = UNSET;
+    }
+  }
+
+  /**
+   *
+   * @param clzName See {@link PSEUDO}
+   * @param status
+   */
+  public void setStatus(String clzName,boolean status){
+    switch (clzName){
+      case Constants.PSEUDO.ACTIVE:
+        setStatus(PesudoStatus.CLASS_ACTIVE,status);
+        break;
+      case Constants.PSEUDO.DISABLED:
+        setStatus(PesudoStatus.CLASS_DISABLED,status);
+        break;
+      case Constants.PSEUDO.ENABLED:
+        setStatus(PesudoStatus.CLASS_ENABLED,status);
+        break;
+      case Constants.PSEUDO.FOCUS:
+        setStatus(PesudoStatus.CLASS_FOCUS,status);
+        break;
+    }
+  }
+
+  void setStatus(int clz,boolean status){
+    mStatuses[clz] = status?SET:UNSET;
+  }
+
+  public boolean isSet(int clz){
+    return mStatuses[clz] == SET;
+  }
+
+  public @Nullable String getStatuses(){
+    StringBuilder sb = new StringBuilder();
+    if(isSet(CLASS_ACTIVE)){
+      sb.append(Constants.PSEUDO.ACTIVE);
+    }
+    if(isSet(CLASS_DISABLED)){
+      sb.append(Constants.PSEUDO.DISABLED);
+    }
+    //enabled is ignored
+
+    if(isSet(CLASS_FOCUS) && !isSet(CLASS_DISABLED)){
+      sb.append(Constants.PSEUDO.FOCUS);
+    }
+    return sb.length()==0?null:sb.toString();
+  }
+
+  public Map<String,Object> updateStatusAndGetUpdateStyles(String clzName,
+                                                           boolean status,
+                                                           Map<String, Map<String,Object>> pesudoStyles,
+                                                           Map<String,Object> originalStyles){
+    String prevStatusesStr = getStatuses();//before change
+    setStatus(clzName,status);
+    String statusesStr = getStatuses();//after change
+
+    Map<String,Object> updateStyles = pesudoStyles.get(statusesStr);
+    Map<String,Object> prevUpdateStyles = pesudoStyles.get(prevStatusesStr);
+
+    /**
+     * NEW INSTANCE, DO NOT USE MAP OBJECT FROM pesudoStyles
+     */
+    Map<String,Object> resultStyles = new ArrayMap<>();
+    if(prevUpdateStyles != null){
+      resultStyles.putAll(prevUpdateStyles);
+    }
+
+    //reset
+    for (String key : resultStyles.keySet()) {
+      resultStyles.put(key, originalStyles.containsKey(key) ? originalStyles.get(key) : "");
+    }
+
+    //apply new update
+    if(updateStyles != null) {
+      for (Map.Entry<String, Object> entry : updateStyles.entrySet()) {
+        resultStyles.put(entry.getKey(), entry.getValue());
+      }
+    }
+    return resultStyles;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/TouchActivePseudoListener.java b/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/TouchActivePseudoListener.java
new file mode 100644
index 0000000..eb92540
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/pesudo/TouchActivePseudoListener.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.pesudo;
+
+import android.annotation.SuppressLint;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * Created by sospartan on 05/01/2017.
+ */
+public class TouchActivePseudoListener implements View.OnTouchListener {
+  private OnActivePseudoListner mOnActivePseudoListner;
+  private boolean mIsConsumeOnTouch;
+
+  public TouchActivePseudoListener(OnActivePseudoListner l, boolean consumeInTouch) {
+    mOnActivePseudoListner = l;
+    mIsConsumeOnTouch = consumeInTouch;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouch(View v, MotionEvent event) {
+    int action = event.getAction();
+    if (mOnActivePseudoListner != null) {
+      if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
+        mOnActivePseudoListner.updateActivePseudo(true);
+      } else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
+        mOnActivePseudoListner.updateActivePseudo(false);
+      }
+    }
+    return mIsConsumeOnTouch;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/WXRichText.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/WXRichText.java
new file mode 100755
index 0000000..0e8180a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/WXRichText.java
@@ -0,0 +1,159 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext;
+
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.TextUtils;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.layout.measurefunc.TextContentBoxMeasurement;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXText;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.component.richtext.node.RichTextNode;
+import org.apache.weex.ui.component.richtext.node.RichTextNodeManager;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class WXRichText extends WXText {
+  private List<RichTextNode> nodes = new LinkedList<>();
+
+  static class RichTextContentBoxMeasurement extends TextContentBoxMeasurement {
+
+    public RichTextContentBoxMeasurement(WXComponent component) {
+      super(component);
+    }
+
+    @NonNull
+    @Override
+    protected Spanned createSpanned(String text) {
+      if(!TextUtils.isEmpty(text)) {
+        if (mComponent.getInstance() != null & mComponent.getInstance().getUIContext() != null &&
+                !TextUtils.isEmpty(mComponent.getInstanceId())) {
+          Spannable spannable = RichTextNode.parse(
+                  mComponent.getInstance().getUIContext(),
+                  mComponent.getInstanceId(),
+                  mComponent.getRef(),
+                  text);
+          updateSpannable(spannable, RichTextNode.createSpanFlag(0));
+          return spannable;
+        } else {
+          return new SpannedString("");
+        }
+      }
+      else {
+        Spannable spannable = ((WXRichText)mComponent).toSpan();
+        updateSpannable(spannable, RichTextNode.createSpanFlag(0));
+        return spannable;
+        }
+    }
+  }
+
+  public static class Creator implements ComponentCreator {
+
+    public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+      return new WXRichText(instance, parent, basicComponentData);
+    }
+  }
+
+  public WXRichText(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+    setContentBoxMeasurement(new RichTextContentBoxMeasurement(this));
+  }
+  public void AddChildNode(String ref, String nodeType,String parentRef, Map<String,String> styles,Map<String,String> attrs) {
+    if(getInstance() != null && getInstance().getUIContext() != null && !TextUtils.isEmpty(getInstanceId()) &&
+            !TextUtils.isEmpty(ref) && !TextUtils.isEmpty(nodeType)) {
+      RichTextNode child = RichTextNodeManager.createRichTextNode(getInstance().getUIContext(), getInstanceId(), getRef(), ref, nodeType, styles, attrs);
+      if (TextUtils.isEmpty(parentRef)) {
+        nodes.add(child);
+      } else {
+        RichTextNode parent = findRichNode(parentRef);
+        if (parent != null) {
+          parent.addChildNode(child);
+        }
+      }
+    }
+  }
+  private Spannable toSpan(){
+    SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
+    if(nodes != null && !nodes.isEmpty()){
+      for(RichTextNode node:nodes){
+        spannableStringBuilder.append(node.toSpan(1));
+      }
+    }
+    return spannableStringBuilder;
+  }
+
+  public void removeChildNode(String parentRef,String ref) {
+    if (nodes != null && !nodes.isEmpty()) {
+      if (parentRef.equals("")) {
+        for (RichTextNode node : nodes) {
+          if (TextUtils.equals(node.getRef(), ref)) {
+            nodes.remove(node);
+          }
+        }
+      } else {
+        RichTextNode parent = findRichNode(parentRef);
+        if (parent != null) {
+          parent.removeChildNode(ref);
+        }
+      }
+    }
+  }
+  public void updateChildNodeStyles(String ref,Map<String,Object> styles){
+    RichTextNode node = findRichNode(ref);
+    if(node != null){
+      node.updateStyles(styles);
+    }
+  }
+  public void updateChildNodeAttrs(String ref,Map<String,Object> attrs){
+    RichTextNode node = findRichNode(ref);
+    if(node != null){
+      node.updateAttrs(attrs);
+    }
+  }
+  private RichTextNode findRichNode(String ref){
+    if(!TextUtils.isEmpty(ref)) {
+      RichTextNode theNode;
+      if (nodes != null && !nodes.isEmpty()) {
+        for (RichTextNode node : nodes) {
+          if ((theNode = node.findRichNode(ref)) != null)
+            return theNode;
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  protected WXRichTextView initComponentHostView(@NonNull Context context) {
+    return new WXRichTextView(context);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/WXRichTextView.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/WXRichTextView.java
new file mode 100644
index 0000000..7ca9e8b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/WXRichTextView.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.Layout;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.style.ClickableSpan;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+import org.apache.weex.ui.component.richtext.span.ImgSpan;
+import org.apache.weex.ui.view.WXTextView;
+
+public class WXRichTextView extends WXTextView {
+
+  public WXRichTextView(Context context) {
+    super(context);
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    boolean superResult = super.onTouchEvent(event);
+    boolean handled = false;
+    if (isEnabled() && getTextLayout() != null && getText() instanceof Spannable) {
+      Spannable spannable = (Spannable) getText();
+      handled = updateSelection(event, spannable);
+    }
+    return handled || superResult;
+  }
+
+  @Override
+  protected boolean verifyDrawable(Drawable who) {
+    super.verifyDrawable(who);
+    return true;
+  }
+
+  @Override
+  public void setTextLayout(Layout layout) {
+    super.setTextLayout(layout);
+    if (layout.getText() instanceof Spanned) {
+      Spanned spanned = (Spanned) layout.getText();
+      ImgSpan[] imgSpan = spanned.getSpans(0, spanned.length(), ImgSpan.class);
+      if (imgSpan != null) {
+        for (ImgSpan span : imgSpan) {
+          span.setView(this);
+        }
+      }
+    }
+  }
+
+  /**
+   * Mostly copied from
+   * {@link android.text.method.LinkMovementMethod#onTouchEvent(TextView, Spannable, MotionEvent)}.
+   */
+  private boolean updateSelection(MotionEvent event, Spannable buffer) {
+    int action = event.getActionMasked();
+
+    if (action == MotionEvent.ACTION_UP ||
+        action == MotionEvent.ACTION_DOWN) {
+      int x = (int) event.getX();
+      int y = (int) event.getY();
+
+      x -= getPaddingLeft();
+      y -= getPaddingTop();
+
+      x += getScrollX();
+      y += getScrollY();
+
+      Layout layout = getTextLayout();
+      int line = layout.getLineForVertical(y);
+      int off = layout.getOffsetForHorizontal(line, x);
+
+      ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
+
+      if (link.length != 0) {
+        if (action == MotionEvent.ACTION_UP) {
+          link[0].onClick(this);
+        } else {
+          Selection.setSelection(buffer,
+                                 buffer.getSpanStart(link[0]),
+                                 buffer.getSpanEnd(link[0]));
+        }
+
+        return true;
+      } else {
+        Selection.removeSelection(buffer);
+      }
+    }
+
+    return false;
+  }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/ANode.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/ANode.java
new file mode 100755
index 0000000..5ecd963
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/ANode.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.node;
+
+import android.content.Context;
+import android.text.SpannableStringBuilder;
+
+import org.apache.weex.ui.component.richtext.span.ASpan;
+import org.apache.weex.ui.component.richtext.span.ItemClickSpan;
+
+import java.util.Map;
+
+class ANode extends RichTextNode {
+
+  static class ANodeCreator implements RichTextNodeCreator<ANode> {
+
+    @Override
+    public ANode createRichTextNode(Context context, String instanceId, String componentRef) {
+      return new ANode(context, instanceId, componentRef);
+    }
+    @Override
+    public ANode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
+                                      Map<String,Object> styles, Map<String,Object> attrs){
+      return new ANode(context,instanceId,componentRef,ref,styles,attrs);
+    }
+
+  }
+
+  public static final String NODE_TYPE = "a";
+  public static final String HREF = "href";
+
+  private ANode(Context context, String instanceId, String componentRef) {
+    super(context, instanceId, componentRef);
+  }
+  private ANode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles, Map<String,Object> attrs) {
+    super(context, instanceId, componentRef, ref, styles, attrs);
+  }
+
+  @Override
+  public String toString() {
+    return "";
+  }
+
+  @Override
+  protected boolean isInternalNode() {
+    return true;
+  }
+
+  @Override
+  protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
+    super.updateSpans(spannableStringBuilder, level);
+      if (attr != null && attr.containsKey(PSEUDO_REF)) {
+          ItemClickSpan itemClickSpan = new ItemClickSpan(mInstanceId, mComponentRef, attr.get(
+              PSEUDO_REF).toString());
+          spannableStringBuilder.setSpan(itemClickSpan, 0, spannableStringBuilder.length(),
+                  createSpanFlag(level));
+      } else if (attr != null && attr.containsKey(HREF)) {
+          ASpan aSpan = new ASpan(mInstanceId, attr.get(HREF).toString());
+          spannableStringBuilder.setSpan(aSpan, 0, spannableStringBuilder.length(),
+                  createSpanFlag(level));
+      }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/ImgNode.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/ImgNode.java
new file mode 100755
index 0000000..c836297
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/ImgNode.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.node;
+
+import static org.apache.weex.utils.WXViewUtils.getRealPxByWidth;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.text.SpannableStringBuilder;
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.DrawableStrategy;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.component.richtext.span.ImgSpan;
+import org.apache.weex.ui.component.richtext.span.ItemClickSpan;
+import org.apache.weex.utils.ImgURIUtil;
+import org.apache.weex.utils.WXUtils;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+class ImgNode extends RichTextNode {
+
+  static class ImgNodeCreator implements RichTextNodeCreator<ImgNode> {
+
+    @Override
+    public ImgNode createRichTextNode(Context context, String instanceId, String componentRef) {
+      return new ImgNode(context, instanceId, componentRef);
+    }
+    @Override
+    public ImgNode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
+                                       Map<String,Object> styles, Map<String,Object> attrs){
+      return new ImgNode(context,instanceId,componentRef,ref,styles,attrs);
+    }
+  }
+
+  public static final String NODE_TYPE = "image";
+
+  private ImgNode(Context context, String instanceId, String componentRef) {
+    super(context, instanceId, componentRef);
+  }
+  private ImgNode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles, Map<String,Object> attrs) {
+    super(context, instanceId, componentRef, ref, styles, attrs);
+  }
+
+  @Override
+  public String toString() {
+    return "\uFEFF";
+  }
+
+  @Override
+  protected boolean isInternalNode() {
+    return false;
+  }
+
+  @Override
+  protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
+    if (WXSDKEngine.getDrawableLoader() != null &&
+        style.containsKey(Constants.Name.WIDTH) &&
+        style.containsKey(Constants.Name.HEIGHT) &&
+        attr.containsKey(Constants.Name.SRC) &&
+        instance != null) {
+      List<Object> spans = new LinkedList<>();
+      spans.add(createImgSpan(instance));
+
+      if (attr.containsKey(PSEUDO_REF)) {
+        spans.add(new ItemClickSpan(mInstanceId, mComponentRef,
+            attr.get(PSEUDO_REF).toString()));
+      }
+
+      for (Object span : spans) {
+        spannableStringBuilder.setSpan(
+            span, 0, spannableStringBuilder.length(), createSpanFlag(level));
+      }
+    }
+  }
+
+  @NonNull
+  private ImgSpan createImgSpan(WXSDKInstance instance) {
+    int width = (int) getRealPxByWidth(WXUtils.getFloat(style.get(Constants.Name.WIDTH)),
+        instance.getInstanceViewPortWidth());
+    int height = (int) getRealPxByWidth(WXUtils.getFloat(style.get(Constants.Name.HEIGHT)),
+        instance.getInstanceViewPortWidth());
+    ImgSpan imageSpan = new ImgSpan(width, height);
+
+    String url = attr.get(Constants.Name.SRC).toString();
+    Uri rewrited = instance.rewriteUri(Uri.parse(url), URIAdapter.IMAGE);
+    if (Constants.Scheme.LOCAL.equals(rewrited.getScheme())) {
+      Drawable localDrawable = ImgURIUtil.getDrawableFromLoaclSrc(mContext, rewrited);
+      imageSpan.setDrawable(localDrawable, false);
+    } else {
+      DrawableStrategy drawableStrategy = new DrawableStrategy();
+      drawableStrategy.width = width;
+      drawableStrategy.height = height;
+      WXSDKEngine.getDrawableLoader().setDrawable(rewrited.toString(), imageSpan, drawableStrategy);
+    }
+    return imageSpan;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNode.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNode.java
new file mode 100755
index 0000000..d0a6e60
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNode.java
@@ -0,0 +1,291 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.node;
+
+import static org.apache.weex.dom.WXStyle.UNSET;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.ForegroundColorSpan;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.WXCustomStyleSpan;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXResourceUtils;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public abstract class RichTextNode {
+
+    public static final String TYPE = "type";
+    public static final String STYLE = "style";
+    public static final String ATTR = "attr";
+    public static final String CHILDREN = "children";
+    public static final String VALUE = Constants.Name.VALUE;
+    public static final String ITEM_CLICK="itemclick";
+    public static final String PSEUDO_REF="pseudoRef";
+    private static final int MAX_LEVEL = Spanned.SPAN_PRIORITY >> Spanned.SPAN_PRIORITY_SHIFT;
+
+    protected final Context mContext;
+    protected final String mInstanceId;
+    protected final String mComponentRef;
+    protected final String mRef;
+    protected Map<String, Object> style;
+    protected Map<String, Object> attr;
+    protected List<RichTextNode> children;
+
+    protected RichTextNode(Context context, String instanceId, String componentRef) {
+        mContext = context;
+        mInstanceId = instanceId;
+        mComponentRef = componentRef;
+        mRef = null;
+    }
+    protected RichTextNode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles, Map<String,Object> attrs) {
+        mContext = context;
+        mInstanceId = instanceId;
+        mComponentRef = componentRef;
+        mRef = ref;
+        if(styles != null){
+            style = styles;
+        }
+        else {
+            style = new ArrayMap<>(0);
+        }
+        if (attrs != null) {
+            attr = attrs;
+        } else {
+            attr = new ArrayMap<>(0);
+        }
+        children = new LinkedList<>();
+    }
+
+    public static
+    @NonNull
+    Spannable parse(@NonNull Context context, @NonNull String instanceId, @NonNull String componentRef, String json) {
+        JSONArray jsonArray = JSON.parseArray(json);
+        JSONObject jsonObject;
+        List<RichTextNode> nodes;
+        RichTextNode node;
+        if (jsonArray != null && !jsonArray.isEmpty()) {
+            nodes = new ArrayList<>(jsonArray.size());
+            for (int i = 0; i < jsonArray.size(); i++) {
+                jsonObject = jsonArray.getJSONObject(i);
+                if (jsonObject != null) {
+                    node = RichTextNodeManager.createRichTextNode(context, instanceId, componentRef, jsonObject);
+                    if (node != null) {
+                        nodes.add(node);
+                    }
+                }
+            }
+            return parse(nodes);
+        }
+        return new SpannableString("");
+    }
+
+    public static int createSpanFlag(int level) {
+        return createPriorityFlag(level) | Spanned.SPAN_INCLUSIVE_EXCLUSIVE;
+    }
+
+    @Override
+    public abstract String toString();
+
+    protected abstract boolean isInternalNode();
+
+    public String getRef(){
+        return mRef;
+    }
+
+    final void parse(@NonNull Context context, @NonNull String instanceId, @NonNull String componentRef, JSONObject jsonObject) {
+        JSONObject jsonStyle, jsonAttr, child;
+        JSONArray jsonChildren;
+        RichTextNode node;
+        if ((jsonStyle = jsonObject.getJSONObject(STYLE)) != null) {
+            style = new ArrayMap<>();
+            style.putAll(jsonStyle);
+        } else {
+            style = new ArrayMap<>(0);
+        }
+
+        if ((jsonAttr = jsonObject.getJSONObject(ATTR)) != null) {
+            attr = new ArrayMap<>(jsonAttr.size());
+            attr.putAll(jsonAttr);
+        } else {
+            attr = new ArrayMap<>(0);
+        }
+
+        if ((jsonChildren=jsonObject.getJSONArray(CHILDREN))!=null) {
+            children = new ArrayList<>(jsonChildren.size());
+            for (int i = 0; i < jsonChildren.size(); i++) {
+                child = jsonChildren.getJSONObject(i);
+                node = RichTextNodeManager.createRichTextNode(context, instanceId, componentRef, child);
+                if (node != null) {
+                    children.add(node);
+                }
+            }
+        } else {
+            children = new ArrayList<>(0);
+        }
+    }
+    public void addChildNode(RichTextNode child){
+        if(children == null){
+            children = new LinkedList<>();
+        }
+        if(child != null && isInternalNode()){
+            children.add(child);
+        }
+    }
+    public void removeChildNode(String ref){
+        if(children != null && !children.isEmpty() && !TextUtils.isEmpty(ref)){
+            try {
+                for (RichTextNode child : children) {
+                    if (TextUtils.equals(child.mRef, ref)) {
+                        children.remove(child);
+                    }
+                }
+            }catch(Exception e){
+                WXLogUtils.getStackTrace(e);
+            }
+        }
+    }
+    public void updateStyles(Map<String,Object> styles){
+        if(styles != null && !styles.isEmpty()){
+            style.putAll(styles);
+        }
+    }
+    public void updateAttrs(Map<String,Object> attrs){
+        if(attr != null && !attrs.isEmpty()){
+            attr.putAll(attrs);
+        }
+    }
+
+    protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
+        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
+        if (style != null && instance != null) {
+            List<Object> spans = new LinkedList<>();
+
+            WXCustomStyleSpan customStyleSpan = createCustomStyleSpan();
+            if (customStyleSpan != null) {
+                spans.add(customStyleSpan);
+            }
+
+            if (style.containsKey(Constants.Name.FONT_SIZE)) {
+                spans.add(new AbsoluteSizeSpan(WXStyle.getFontSize(style, instance.getInstanceViewPortWidth())));
+            }
+
+            if (style.containsKey(Constants.Name.BACKGROUND_COLOR)) {
+                int color = WXResourceUtils.getColor(style.get(Constants.Name.BACKGROUND_COLOR).toString(),
+                    Color.TRANSPARENT);
+                if (color != Color.TRANSPARENT) {
+                    spans.add(new BackgroundColorSpan(color));
+                }
+            }
+
+            if (style.containsKey(Constants.Name.COLOR)) {
+                spans.add(new ForegroundColorSpan(WXResourceUtils.getColor(WXStyle.getTextColor(style))));
+            }
+
+            int spanFlag = createSpanFlag(level);
+            for (Object span : spans) {
+                spannableStringBuilder.setSpan(span, 0, spannableStringBuilder.length(), spanFlag);
+            }
+        }
+    }
+
+    private static int createPriorityFlag(int level) {
+        return level <= MAX_LEVEL ?
+            (MAX_LEVEL - level) << Spanned.SPAN_PRIORITY_SHIFT :
+            MAX_LEVEL << Spanned.SPAN_PRIORITY_SHIFT;
+    }
+
+
+    private static
+    @NonNull
+    Spannable parse(@NonNull List<RichTextNode> list) {
+        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
+        for (RichTextNode richTextNode : list) {
+            spannableStringBuilder.append(richTextNode.toSpan(1));
+        }
+        return spannableStringBuilder;
+    }
+
+    public Spannable toSpan(int level) {
+        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
+        spannableStringBuilder.append(toString());
+        if (isInternalNode() && children != null) {
+            for (RichTextNode child : children) {
+                spannableStringBuilder.append(child.toSpan(level + 1));
+            }
+        }
+        updateSpans(spannableStringBuilder, level);
+        return spannableStringBuilder;
+    }
+
+    private
+    @Nullable
+    WXCustomStyleSpan createCustomStyleSpan() {
+        int fontWeight = UNSET, fontStyle = UNSET;
+        String fontFamily = null;
+        if (style.containsKey(Constants.Name.FONT_WEIGHT)) {
+            fontWeight = WXStyle.getFontWeight(style);
+        }
+        if (style.containsKey(Constants.Name.FONT_STYLE)) {
+            fontStyle = WXStyle.getFontStyle(style);
+        }
+        if (style.containsKey(Constants.Name.FONT_FAMILY)) {
+            fontFamily = WXStyle.getFontFamily(style);
+        }
+        if (fontWeight != UNSET
+            || fontStyle != UNSET
+            || fontFamily != null) {
+            return new WXCustomStyleSpan(fontStyle, fontWeight, fontFamily);
+        } else {
+            return null;
+        }
+    }
+    public RichTextNode findRichNode(String ref){
+        RichTextNode theNode;
+        if(mRef != null && TextUtils.equals(mRef,ref)){
+            return this;
+        }
+        if(children != null && !children.isEmpty()){
+            for (RichTextNode child:children) {
+                if((theNode = child.findRichNode(ref)) != null)
+                    return theNode;
+            }
+        }
+        return null;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNodeCreator.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNodeCreator.java
new file mode 100755
index 0000000..a1d3313
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNodeCreator.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.node;
+
+import android.content.Context;
+
+import java.util.Map;
+
+public interface RichTextNodeCreator<T extends RichTextNode> {
+
+  T createRichTextNode(Context context, String instanceId, String componentRef);
+  T createRichTextNode(Context context,String instanceId,String componentRef,String ref,Map<String,Object> styles, Map<String,Object> attrs);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNodeManager.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNodeManager.java
new file mode 100755
index 0000000..24c69f9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/RichTextNodeManager.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.node;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.Map;
+
+public class RichTextNodeManager {
+
+  private final static Map<String, RichTextNodeCreator>
+      registeredTextNodes = new ArrayMap<>();
+
+  static {
+    registeredTextNodes.put(SpanNode.NODE_TYPE, new SpanNode.SpanNodeCreator());
+    registeredTextNodes.put(ImgNode.NODE_TYPE, new ImgNode.ImgNodeCreator());
+    registeredTextNodes.put(ANode.NODE_TYPE, new ANode.ANodeCreator());
+  }
+
+  public static void registerTextNode(String text, RichTextNodeCreator type) {
+    registeredTextNodes.put(text, type);
+  }
+
+  @Nullable
+  static RichTextNode createRichTextNode(@NonNull Context context, @NonNull String instanceId,
+      @NonNull String componentRef, @Nullable JSONObject jsonObject) {
+    RichTextNode instance = null;
+    try {
+      if (jsonObject != null) {
+        instance = registeredTextNodes.get(jsonObject.getString(RichTextNode.TYPE))
+            .createRichTextNode(context, instanceId, componentRef);
+        instance.parse(context, instanceId, componentRef, jsonObject);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("Richtext", WXLogUtils.getStackTrace(e));
+      instance = null;
+    }
+    return instance;
+  }
+  public static RichTextNode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
+                                         String nodeType,Map<String,String> styles,Map<String,String> attrs){
+    RichTextNode instance;
+    try{
+      instance = registeredTextNodes.get(nodeType).createRichTextNode(context,instanceId,componentRef,ref,styles,attrs);
+    }catch (Exception e){
+      WXLogUtils.e("Richtext", WXLogUtils.getStackTrace(e));
+      instance = null;
+    }
+    return instance;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/SpanNode.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/SpanNode.java
new file mode 100755
index 0000000..6f0d499
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/node/SpanNode.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.node;
+
+import android.content.Context;
+import android.text.SpannableStringBuilder;
+
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.TextDecorationSpan;
+import org.apache.weex.dom.WXStyle;
+
+import java.util.Map;
+
+class SpanNode extends RichTextNode {
+
+  static class SpanNodeCreator implements RichTextNodeCreator<SpanNode> {
+
+    @Override
+    public SpanNode createRichTextNode(Context context, String instanceId, String componentRef) {
+      return new SpanNode(context, instanceId, componentRef);
+    }
+
+    @Override
+    public SpanNode createRichTextNode(Context context,String instanceId,String componentRef,String ref,
+                                       Map<String,Object> styles, Map<String,Object> attrs){
+      return new SpanNode(context,instanceId,componentRef,ref,styles,attrs);
+    }
+  }
+
+  public static final String NODE_TYPE = "span";
+
+  private SpanNode(Context context, String instanceId, String componentRef) {
+    super(context, instanceId, componentRef);
+  }
+  private SpanNode(Context context, String instanceId, String componentRef, String ref, Map<String,Object> styles,Map<String,Object> attrs) {
+    super(context, instanceId, componentRef, ref, styles, attrs);
+  }
+
+  @Override
+  public String toString() {
+    if (attr == null || !attr.containsKey(Constants.Name.VALUE)) {
+      return "";
+    } else {
+      return attr.get(Constants.Name.VALUE).toString();
+    }
+  }
+
+  @Override
+  protected boolean isInternalNode() {
+    return true;
+  }
+
+  @Override
+  protected void updateSpans(SpannableStringBuilder spannableStringBuilder, int level) {
+    super.updateSpans(spannableStringBuilder, level);
+    spannableStringBuilder.setSpan(new TextDecorationSpan(WXStyle.getTextDecoration(style)), 0,
+        spannableStringBuilder.length(), createSpanFlag(level));
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ASpan.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ASpan.java
new file mode 100644
index 0000000..2a4e7b4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ASpan.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.span;
+
+import android.text.TextPaint;
+import android.text.style.ClickableSpan;
+import android.view.View;
+import org.apache.weex.utils.ATagUtil;
+
+public class ASpan extends ClickableSpan {
+
+  private String mInstanceId, mURL;
+
+  public ASpan(String instanceId, String url) {
+    mInstanceId = instanceId;
+    mURL = url;
+  }
+
+  @Override
+  public void onClick(View widget) {
+    ATagUtil.onClick(widget, mInstanceId, mURL);
+  }
+
+  /**
+   Override super method and do nothing. As no default color or text-decoration is needed.
+   */
+  @Override
+  public void updateDrawState(TextPaint ds) {
+
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ImgSpan.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ImgSpan.java
new file mode 100644
index 0000000..d27b202
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ImgSpan.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.span;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.text.style.ReplacementSpan;
+import android.view.View;
+
+import org.apache.weex.adapter.IDrawableLoader.StaticTarget;
+
+
+public class ImgSpan extends ReplacementSpan implements StaticTarget {
+
+  private int width, height;
+  private Drawable mDrawable;
+  private View mView;
+
+  public ImgSpan(int width, int height) {
+    this.width = width;
+    this.height = height;
+  }
+
+  /**
+   * Mostly copied from
+   *
+   * {@link android.text.style.DynamicDrawableSpan#getSize(Paint, CharSequence, int, int, Paint.FontMetricsInt)},
+   * but not use Drawable to calculate size;
+   */
+  @Override
+  public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
+    if (fm != null) {
+      fm.ascent = -height;
+      fm.descent = 0;
+
+      fm.top = fm.ascent;
+      fm.bottom = 0;
+    }
+    return width;
+  }
+
+  /**
+   * Mostly copied from
+   * {@link android.text.style.DynamicDrawableSpan#draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)},
+   * except for vertical alignment.
+   */
+  @Override
+  public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
+    if (mDrawable != null) {
+      canvas.save();
+      int transY = bottom - mDrawable.getBounds().bottom;
+      transY -= paint.getFontMetricsInt().descent;
+      canvas.translate(x, transY);
+      mDrawable.draw(canvas);
+      canvas.restore();
+    }
+  }
+
+  @Override
+  public void setDrawable(Drawable drawable, boolean resetBounds) {
+    mDrawable = drawable;
+    if(resetBounds) {
+      mDrawable.setBounds(0, 0, width, height);
+    }
+    setCallback();
+    mDrawable.invalidateSelf();
+  }
+
+  public void setView(View view) {
+    mView = view;
+    setCallback();
+  }
+
+  private void setCallback() {
+    if (mDrawable != null && mView != null) {
+      mDrawable.setCallback(mView);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ItemClickSpan.java b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ItemClickSpan.java
new file mode 100644
index 0000000..6e6286c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/component/richtext/span/ItemClickSpan.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.component.richtext.span;
+
+
+import android.text.style.ClickableSpan;
+import android.view.View;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.ui.component.richtext.node.RichTextNode;
+import org.apache.weex.utils.WXDataStructureUtil;
+import java.util.Map;
+
+public class ItemClickSpan extends ClickableSpan {
+
+  private final String mPseudoRef;
+  private final String mInstanceId;
+  private final String mComponentRef;
+
+  public ItemClickSpan(String instanceId, String componentRef, String pseudoRef) {
+    this.mPseudoRef = pseudoRef;
+    this.mInstanceId = instanceId;
+    this.mComponentRef = componentRef;
+  }
+
+  @Override
+  public void onClick(View widget) {
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
+    if (instance != null && !instance.isDestroy()) {
+      Map<String, Object> param = WXDataStructureUtil.newHashMapWithExpectedSize(1);
+      param.put(RichTextNode.PSEUDO_REF, mPseudoRef);
+      instance.fireEvent(mComponentRef, RichTextNode.ITEM_CLICK, param);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/config/AutoScanConfigRegister.java b/android/sdk/src/main/java/org/apache/weex/ui/config/AutoScanConfigRegister.java
new file mode 100644
index 0000000..26477d0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/config/AutoScanConfigRegister.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.config;
+
+import android.content.res.AssetManager;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.utils.WXFileUtils;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.io.IOException;
+
+/**
+ * Created by furture on 2018/2/7.
+ */
+
+public class AutoScanConfigRegister {
+
+    private static long scanDelay = 0;
+
+    public static final  String TAG  = "WeexScanConfigRegister";
+
+
+    /**
+     * auto scan config files and do auto config from files, none need center register
+     * */
+    public static void doScanConfig(){
+        if(scanDelay > 0){
+            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    doScanConfigAsync();
+                }
+            }, scanDelay);
+        }else{
+            doScanConfigAsync();
+        }
+    }
+
+    public static void doScanConfigAsync(){
+        Thread thread = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                doScanConfigSync();
+            }
+        });
+        thread.setName("AutoScanConfigRegister");
+        thread.start();
+    }
+
+    private static void doScanConfigSync(){
+        if(WXEnvironment.sApplication == null){
+            return;
+        }
+        try{
+            AssetManager assetManager = WXEnvironment.sApplication.getApplicationContext().getAssets();
+
+            String[] configFiles = new String[0];
+            try {
+                configFiles = assetManager.list("");
+            } catch (IOException e) {
+                WXLogUtils.e(TAG, e);
+            }
+            if(configFiles == null || configFiles.length == 0){
+                return;
+            }
+            for(String configFile : configFiles){
+                if(TextUtils.isEmpty(configFile)){
+                    continue;
+                }
+                if(configFile.startsWith("weex_config_") && configFile.endsWith(".json")){
+                    String name = configFile;
+                    if(TextUtils.isEmpty(name)){
+                        return;
+                    }
+                    try {
+                        String config = WXFileUtils.loadAsset(name, WXEnvironment.getApplication());
+                        if (TextUtils.isEmpty(config)) {
+                            continue;
+                        }
+                        if (WXEnvironment.isApkDebugable()) {
+                            WXLogUtils.d(TAG, configFile + " find config " + config);
+                        }
+                        JSONObject object = JSON.parseObject(config);
+                        if (object.containsKey("modules")) {
+                            JSONArray array = object.getJSONArray("modules");
+                            for (int i = 0; i < array.size(); i++) {
+                                ConfigModuleFactory configModuleFactory = ConfigModuleFactory.fromConfig(array.getJSONObject(i));
+                                if (configModuleFactory == null) {
+                                    continue;
+                                }
+                                WXSDKEngine.registerModule(configModuleFactory.getName(), configModuleFactory, false);
+                            }
+                        }
+
+                        if (object.containsKey("components")) {
+                            JSONArray array = object.getJSONArray("components");
+                            for (int i = 0; i < array.size(); i++) {
+                                ConfigComponentHolder configComponentHolder = ConfigComponentHolder.fromConfig(array.getJSONObject(i));
+                                if (configComponentHolder == null) {
+                                    return;
+                                }
+                                WXSDKEngine.registerComponent(configComponentHolder, configComponentHolder.isAppendTree(), configComponentHolder.getType());
+                            }
+                        }
+                    }catch (Throwable e){
+                        WXLogUtils.e(TAG, e);
+                    }
+                }
+            }
+        }catch (Exception eout){
+            WXLogUtils.e(TAG, eout);
+        }
+    }
+
+    public static void setScanDelay(long scanDelay) {
+        AutoScanConfigRegister.scanDelay = scanDelay;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/config/ConfigComponentHolder.java b/android/sdk/src/main/java/org/apache/weex/ui/config/ConfigComponentHolder.java
new file mode 100644
index 0000000..16759eb
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/config/ConfigComponentHolder.java
@@ -0,0 +1,162 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.config;
+
+import android.text.TextUtils;
+import android.util.Pair;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.bridge.Invoker;
+import org.apache.weex.ui.ComponentCreator;
+import org.apache.weex.ui.IFComponentHolder;
+import org.apache.weex.ui.SimpleComponentHolder;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+/**
+ * Created by furture on 2018/2/7.
+ */
+public class ConfigComponentHolder implements IFComponentHolder {
+
+
+    public static final String TAG = AutoScanConfigRegister.TAG;
+    private Map<String, Invoker> mPropertyInvokers;
+    private Map<String, Invoker> mMethodInvokers;
+
+    private ClassLoader mClassLoader;
+
+    private String mType;
+    private boolean mAppendTree;
+    private String mClassName;
+    private String[] methods;
+    private Class mClass;
+
+    public ConfigComponentHolder(String mType, boolean mAppendTree, String mClassName, String[] methods) {
+        this.mType = mType;
+        this.mAppendTree = mAppendTree;
+        this.mClassName = mClassName;
+        this.methods = methods;
+    }
+
+    @Override
+    public void loadIfNonLazy() {
+    }
+
+    private synchronized boolean generate(){
+        if(mClass == null){
+            return false;
+        }
+
+        Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = SimpleComponentHolder.getMethods(mClass);
+        mPropertyInvokers = methodPair.first;
+        mMethodInvokers = methodPair.second;
+        return true;
+    }
+
+
+
+    @Override
+    public synchronized WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+        if(mClass == null || mClassLoader != instance.getContext().getClassLoader()){
+            mClass = WXSDKManager
+                .getInstance().getClassLoaderAdapter().getComponentClass(mType, mClassName, instance);
+            mClassLoader = instance.getContext().getClassLoader();
+        }
+        ComponentCreator creator = new SimpleComponentHolder.ClazzComponentCreator(mClass);
+        WXComponent component = creator.createInstance(instance, parent, basicComponentData);
+
+        component.bindHolder(this);
+        return component;
+    }
+
+    @Override
+    public synchronized Invoker getPropertyInvoker(String name){
+        if (mPropertyInvokers == null && !generate()) {
+            return null;
+        }
+
+        return mPropertyInvokers.get(name);
+    }
+
+    @Override
+    public Invoker getMethodInvoker(String name) {
+        if(mMethodInvokers == null && !generate()){
+            return null;
+        }
+        return mMethodInvokers.get(name);
+    }
+
+    @Override
+    public String[] getMethods() {
+        if(methods == null){
+            //generate failed
+            return new String[0];
+        }
+        return methods;
+    }
+
+
+    public static final ConfigComponentHolder fromConfig(JSONObject config){
+        if(config == null){
+            return null;
+        }
+        try{
+            String type = config.getString("name");
+            boolean appendTree  = config.getBooleanValue("appendTree");
+            String className = config.getString("className");
+            JSONArray methods =  null;
+            if(config.containsKey("methods")) {
+                methods = config.getJSONArray("methods");
+            }
+            if(TextUtils.isEmpty(type) || TextUtils.isEmpty(className)){
+                return null;
+            }
+            String[]  arrays = new String[0];
+            if(methods != null){
+                arrays = new String[methods.size()];
+                methods.toArray(arrays);
+            }
+            if(WXEnvironment.isApkDebugable()){
+                WXLogUtils.d(TAG, "resolve component " + type + " className " + className +  " methods " + methods);
+            }
+            return new ConfigComponentHolder(type, appendTree, className, arrays);
+        }catch (Exception e){
+            WXLogUtils.e(TAG, e);
+            return null;
+        }
+
+    }
+
+    public boolean isAppendTree() {
+        return mAppendTree;
+    }
+
+    public String getType() {
+        return mType;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/config/ConfigModuleFactory.java b/android/sdk/src/main/java/org/apache/weex/ui/config/ConfigModuleFactory.java
new file mode 100644
index 0000000..c3973ee
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/config/ConfigModuleFactory.java
@@ -0,0 +1,157 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.config;
+
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.Invoker;
+import org.apache.weex.bridge.MethodInvoker;
+import org.apache.weex.bridge.ModuleFactory;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.common.WXModuleAnno;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by furture on 2018/2/7.
+ */
+
+public class ConfigModuleFactory<T extends WXModule> implements ModuleFactory<T> {
+
+    public static final String TAG = AutoScanConfigRegister.TAG;
+
+    private String mName;
+    private String mClassName;
+    private String[] methods;
+    private Class<T> mClazz;
+    private Map<String, Invoker> mMethodMap;
+
+    private ClassLoader mClassLoader;
+
+    public ConfigModuleFactory(String mName, String mClassName, String[] methods) {
+        this.mName = mName;
+        this.mClassName = mClassName;
+        this.methods = methods;
+    }
+
+    @Override
+    public String[] getMethods() {
+        if(methods == null){
+            return new String[0];
+        }
+        return methods;
+    }
+
+    @Override
+    public Invoker getMethodInvoker(String name) {
+        if (mMethodMap == null) {
+            generateMethodMap();
+        }
+        return mMethodMap.get(name);
+    }
+
+    @Override
+    public T buildInstance() throws IllegalAccessException, InstantiationException {
+        if(mClazz == null){
+            mClazz = (Class<T>) WXSDKManager
+                .getInstance().getClassLoaderAdapter().getModuleClass(mName, mClassName, WXEnvironment
+                    .getApplication().getApplicationContext());
+        }
+        return mClazz.newInstance();
+    }
+
+    public T buildInstance(WXSDKInstance instance) throws IllegalAccessException, InstantiationException {
+        if(instance == null){
+            return buildInstance();
+        }
+        if(mClazz == null || mClassLoader != instance.getContext().getClassLoader()){
+            mClazz = (Class<T>) WXSDKManager.getInstance().getClassLoaderAdapter().getModuleClass(mName, mClassName, instance.getContext());
+            mClassLoader = instance.getContext().getClassLoader();
+        }
+        return mClazz.newInstance();
+    }
+
+
+    private void generateMethodMap() {
+        if(WXEnvironment.isApkDebugable()) {
+             WXLogUtils.d(TAG, "extractMethodNames:" + mClazz.getSimpleName());
+        }
+        HashMap<String, Invoker> methodMap = new HashMap<>();
+        try {
+            for (Method method : mClazz.getMethods()) {
+                // iterates all the annotations available in the method
+                for (Annotation anno : method.getDeclaredAnnotations()) {
+                    if (anno != null) {
+                        if(anno instanceof JSMethod) {
+                            JSMethod methodAnnotation = (JSMethod) anno;
+                            String name = JSMethod.NOT_SET.equals(methodAnnotation.alias())? method.getName():methodAnnotation.alias();
+                            methodMap.put(name, new MethodInvoker(method, methodAnnotation.uiThread()));
+                            break;
+                        }else if(anno instanceof WXModuleAnno) {
+                            WXModuleAnno methodAnnotation = (WXModuleAnno)anno;
+                            methodMap.put(method.getName(), new MethodInvoker(method,methodAnnotation.runOnUIThread()));
+                            break;
+                        }
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            WXLogUtils.e("[WXModuleManager] extractMethodNames:", e);
+        }
+        mMethodMap = methodMap;
+    }
+
+
+    public static ConfigModuleFactory fromConfig(JSONObject config){
+        try{
+            if(config == null){
+                return null;
+            }
+
+            String name = config.getString("name");
+            String className = config.getString("className");
+            JSONArray methods = config.getJSONArray("methods");
+            if(TextUtils.isEmpty(name) || TextUtils.isEmpty(className)){
+                return null;
+            }
+            String[]  arrays = new String[methods.size()];
+            if(WXEnvironment.isApkDebugable()){
+                WXLogUtils.d(TAG, " resolve module " + name + " className " + className +  " methods " + methods);
+            }
+            return new ConfigModuleFactory(name, className, methods.toArray(arrays));
+        }catch (Exception e){
+             WXLogUtils.e(TAG, e);
+             return null;
+        }
+    }
+
+    public String getName() {
+        return mName;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/FlatComponent.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/FlatComponent.java
new file mode 100644
index 0000000..f18b149
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/FlatComponent.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat;
+
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+import org.apache.weex.ui.flat.widget.Widget;
+
+@RestrictTo(Scope.LIBRARY)
+public interface FlatComponent<T extends Widget> {
+
+  boolean promoteToView(boolean checkAncestor);
+
+  @NonNull
+  T getOrCreateFlatWidget();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/FlatGUIContext.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/FlatGUIContext.java
new file mode 100644
index 0000000..9bb3dda
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/FlatGUIContext.java
@@ -0,0 +1,146 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat;
+
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.view.View;
+
+import org.apache.weex.common.Constants.Name;
+import org.apache.weex.common.Destroyable;
+import org.apache.weex.dom.WXAttr;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.flat.widget.AndroidViewWidget;
+import org.apache.weex.ui.flat.widget.Widget;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+//TODO The constructor of FlatGUIContext should have a flag decide whether to enable flagGUI.
+
+@RestrictTo(Scope.LIBRARY)
+public class FlatGUIContext implements Destroyable {
+
+  private Map<WXComponent, WidgetContainer> mWidgetRegistry = new ArrayMap<>();
+  private Map<WXComponent, AndroidViewWidget> mViewWidgetRegistry = new ArrayMap<>();
+  private Map<Widget, WXComponent> widgetToComponent = new ArrayMap<>();
+
+  public boolean isFlatUIEnabled(WXComponent component) {
+    return false;
+  }
+
+  public void register(@NonNull WXComponent descendant, @NonNull WidgetContainer ancestor) {
+    if (!(ancestor instanceof FlatComponent) ||
+            ((FlatComponent) ancestor).promoteToView(true)) {
+      mWidgetRegistry.put(descendant, ancestor);
+    }
+  }
+
+  public void register(@NonNull WXComponent component, @NonNull AndroidViewWidget viewWidget) {
+    mViewWidgetRegistry.put(component, viewWidget);
+  }
+
+  public void register(@NonNull Widget widget, @NonNull WXComponent component) {
+    widgetToComponent.put(widget, component);
+  }
+
+  public
+  @Nullable
+  WidgetContainer getFlatComponentAncestor(@NonNull WXComponent flatWidget) {
+    return mWidgetRegistry.get(flatWidget);
+  }
+
+  public
+  @Nullable
+  AndroidViewWidget getAndroidViewWidget(@NonNull WXComponent component) {
+    return mViewWidgetRegistry.get(component);
+  }
+
+  public boolean promoteToView(@NonNull WXComponent component, boolean checkAncestor,
+                               @NonNull Class<? extends WXComponent<?>> expectedClass) {
+    return !isFlatUIEnabled(component) ||
+            !expectedClass.equals(component.getClass()) ||
+            TextUtils.equals(component.getRef(), WXComponent.ROOT) ||
+            (checkAncestor && getFlatComponentAncestor(component) == null) ||
+            checkComponent(component);
+  }
+
+  public
+  @Nullable
+  View getWidgetContainerView(Widget widget) {
+    WXComponent component, ancestor;
+    View ret = null;
+    if ((component = getComponent(widget)) != null) {
+      if ((ancestor = getFlatComponentAncestor(component)) != null) {
+        ret = ancestor.getHostView();
+      }
+    }
+    return ret;
+  }
+
+  @Override
+  @RestrictTo(Scope.LIBRARY)
+  public void destroy() {
+    widgetToComponent.clear();
+
+    for (Entry<WXComponent, AndroidViewWidget> entry : mViewWidgetRegistry.entrySet()) {
+      entry.getValue().destroy();
+    }
+    mViewWidgetRegistry.clear();
+
+    for (Entry<WXComponent, WidgetContainer> entry : mWidgetRegistry.entrySet()) {
+      entry.getValue().unmountFlatGUI();
+    }
+    mWidgetRegistry.clear();
+  }
+
+  private @Nullable
+  WXComponent getComponent(@NonNull Widget widget) {
+    return widgetToComponent.get(widget);
+  }
+
+  private boolean checkComponent(@NonNull WXComponent component) {
+    boolean ret = false;
+    if (component != null) {
+      WXStyle style = component.getStyles();
+      WXAttr attr = component.getAttrs();
+      if (style.containsKey(Name.OPACITY) ||
+              style.containsKey(Name.TRANSFORM) ||
+              style.containsKey(Name.VISIBILITY) ||
+              attr.containsKey(Name.ELEVATION) ||
+              attr.containsKey(Name.ARIA_HIDDEN) ||
+              attr.containsKey(Name.ARIA_LABEL) ||
+              attr.containsKey(WXComponent.PROP_FIXED_SIZE) ||
+              attr.containsKey(Name.DISABLED) ||
+              style.isFixed() ||
+              style.isSticky() ||
+              !style.getPesudoStyles().isEmpty() ||
+              component.getEvents().size() > 0) {
+        ret = true;
+      }
+    }
+    return ret;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/WidgetContainer.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/WidgetContainer.java
new file mode 100644
index 0000000..58b8e0d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/WidgetContainer.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat;
+
+
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.util.Pair;
+import android.view.ViewGroup;
+
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.ui.action.BasicComponentData;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXVContainer;
+import org.apache.weex.ui.flat.widget.AndroidViewWidget;
+import org.apache.weex.ui.flat.widget.Widget;
+
+import java.util.LinkedList;
+import java.util.List;
+
+@RestrictTo(Scope.LIBRARY)
+public abstract class WidgetContainer<T extends ViewGroup> extends WXVContainer<T> {
+
+  protected List<Widget> widgets;
+
+  public WidgetContainer(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
+    super(instance, parent, basicComponentData);
+  }
+
+  protected abstract void mountFlatGUI();
+
+  protected abstract void unmountFlatGUI();
+
+  public boolean intendToBeFlatContainer() {
+    return false;
+  }
+
+  @Override
+  public void createChildViewAt(int index) {
+    if (intendToBeFlatContainer()) {
+      Pair<WXComponent, Integer> ret = rearrangeIndexAndGetChild(index);
+      if (ret.first != null) {
+        WXComponent child = ret.first;
+        Widget flatChild;
+        FlatGUIContext uiImp = getInstance().getFlatUIContext();
+        WidgetContainer parent = uiImp.getFlatComponentAncestor(this);
+        if (parent == null || uiImp.getAndroidViewWidget(this) != null) {
+          parent = this;
+        }
+        uiImp.register(child, parent);
+
+        if (child instanceof FlatComponent && !((FlatComponent) child).promoteToView(false)) {
+          flatChild = ((FlatComponent) child).getOrCreateFlatWidget();
+        } else {
+          flatChild = new AndroidViewWidget(uiImp);
+          uiImp.register(child, (AndroidViewWidget) flatChild);
+          child.createView();
+          ((AndroidViewWidget) flatChild).setContentView(child.getHostView());
+          //TODO Use a sort algorithm to decide the childIndex of AndroidViewWidget
+          parent.addSubView(child.getHostView(), -1);
+        }
+        uiImp.register(flatChild, child);
+        addFlatChild(flatChild, ret.second);
+      }
+    } else {
+      super.createChildViewAt(index);
+    }
+  }
+
+  private void addFlatChild(Widget widget, int index) {
+    if(widgets == null){
+      widgets = new LinkedList<>();
+    }
+    if (index >= widgets.size()) {
+      widgets.add(widget);
+    } else {
+      widgets.add(index, widget);
+    }
+    //TODO do a partial update, not mount the whole flatContainer.
+    mountFlatGUI();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/AndroidViewWidget.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/AndroidViewWidget.java
new file mode 100644
index 0000000..f2682de
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/AndroidViewWidget.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat.widget;
+
+
+import android.graphics.Canvas;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.view.View;
+
+import org.apache.weex.common.Destroyable;
+import org.apache.weex.ui.flat.FlatGUIContext;
+
+@RestrictTo(Scope.LIBRARY)
+public class AndroidViewWidget extends BaseWidget implements Destroyable {
+
+  private @Nullable
+  View mView;
+
+  public AndroidViewWidget(@NonNull FlatGUIContext context) {
+    super(context);
+  }
+
+  public void setContentView(@Nullable View view) {
+    this.mView = view;
+  }
+
+  @Override
+  public void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset) {
+    if (mView != null) {
+      mView.setPadding(leftOffset, topOffset, rightOffset, bottomOffset);
+      invalidate();
+    }
+  }
+
+  @Override
+  public void onDraw(@NonNull Canvas canvas) {
+    if (mView != null) {
+      mView.draw(canvas);
+    }
+  }
+
+  @Override
+  public void invalidate() {
+    super.invalidate();
+    if (mView != null) {
+      mView.invalidate();
+    }
+  }
+
+  public @Nullable
+  View getView() {
+    return mView;
+  }
+
+  @Override
+  public void destroy() {
+    if (mView != null) {
+      mView = null;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/BaseWidget.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/BaseWidget.java
new file mode 100644
index 0000000..c766a5d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/BaseWidget.java
@@ -0,0 +1,130 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat.widget;
+
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.view.View;
+import org.apache.weex.ui.flat.FlatGUIContext;
+import org.apache.weex.ui.view.border.BorderDrawable;
+import org.apache.weex.utils.WXViewUtils;
+
+@RestrictTo(Scope.LIBRARY)
+abstract class BaseWidget implements Widget {
+
+  //TODO Reconsider the field parameter in this class and the operation during draw(); Make a CPU/Memory balance.
+  //TODO use float to avoid 1px problem
+  private BorderDrawable backgroundBorder;
+  private int leftOffset, topOffset, rightOffset, bottomOffset;
+  private Rect borderBox = new Rect();
+  private Point offsetOfContainer = new Point();
+  private final @NonNull
+  FlatGUIContext context;
+
+  BaseWidget(@NonNull FlatGUIContext context){
+    this.context = context;
+  }
+
+  @Override
+  public void setLayout(int width, int height, int left, int right, int top, int bottom, Point offset) {
+    this.offsetOfContainer = offset;
+    borderBox.set(left, top, left + width, top + height);
+    if (backgroundBorder != null) {
+      setBackgroundAndBorder(backgroundBorder);
+    }
+    invalidate();
+  }
+
+  @Override
+  public void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset) {
+    this.leftOffset = leftOffset;
+    this.topOffset = topOffset;
+    this.rightOffset = rightOffset;
+    this.bottomOffset = bottomOffset;
+    invalidate();
+  }
+
+  @Override
+  public void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder) {
+    //TODO Change the code of BorderDrawable is more appropriate as it draws the borderLine from (0,0) not from getBounds
+    //TODO If the above is finished, no more traslate in draw in needed, only clip is enough.
+    this.backgroundBorder = backgroundBorder;
+    Rect backgroundBox = new Rect(borderBox);
+    backgroundBox.offset(-borderBox.left, -borderBox.top);
+    backgroundBorder.setBounds(backgroundBox);
+    setCallback(backgroundBorder);
+    invalidate();
+  }
+
+  @NonNull
+  @Override
+  public final Point getLocInFlatContainer() {
+    return offsetOfContainer;
+  }
+
+  @Nullable
+  @Override
+  public final BorderDrawable getBackgroundAndBorder() {
+    return backgroundBorder;
+  }
+
+  @NonNull
+  @Override
+  public final Rect getBorderBox() {
+    return borderBox;
+  }
+
+  @Override
+  public final void draw(@NonNull Canvas canvas) {
+    canvas.save();
+    WXViewUtils.clipCanvasWithinBorderBox(this, canvas);
+    canvas.translate(borderBox.left, borderBox.top);
+    if (backgroundBorder != null) {
+      backgroundBorder.draw(canvas);
+    }
+    canvas.clipRect(leftOffset, topOffset, borderBox.width()-rightOffset, borderBox.height() - bottomOffset);
+    canvas.translate(leftOffset, topOffset);
+    onDraw(canvas);
+    canvas.restore();
+  }
+
+  protected void invalidate() {
+    Rect dirtyRegion = new Rect(borderBox);
+    dirtyRegion.offset(offsetOfContainer.x, offsetOfContainer.y);
+    View widgetContainer;
+    if (context != null && (widgetContainer = context.getWidgetContainerView(this)) != null) {
+      widgetContainer.invalidate(dirtyRegion);
+    }
+  }
+
+  protected void setCallback(@NonNull Drawable drawable) {
+    View widgetContainer;
+    if (context != null && (widgetContainer = context.getWidgetContainerView(this)) != null) {
+      drawable.setCallback(widgetContainer);
+    }
+  }
+}
+
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/TextWidget.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/TextWidget.java
new file mode 100644
index 0000000..30b0faf
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/TextWidget.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat.widget;
+
+
+import android.graphics.Canvas;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.text.Layout;
+
+import org.apache.weex.ui.flat.FlatGUIContext;
+
+@RestrictTo(Scope.LIBRARY)
+public class TextWidget extends BaseWidget {
+
+  private Layout mLayout;
+
+  public TextWidget(@NonNull FlatGUIContext context) {
+    super(context);
+  }
+
+  @Override
+  public void onDraw(@NonNull Canvas canvas) {
+    if (mLayout != null) {
+      mLayout.draw(canvas);
+    }
+  }
+
+  public void updateTextDrawable(Layout layout) {
+    this.mLayout = layout;
+    invalidate();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/Widget.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/Widget.java
new file mode 100644
index 0000000..73e3993
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/Widget.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat.widget;
+
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+import org.apache.weex.ui.view.border.BorderDrawable;
+
+@RestrictTo(Scope.LIBRARY)
+public interface Widget {
+
+  public static final String TAG = "Widget";
+
+  void draw(@NonNull Canvas canvas);
+
+  void onDraw(@NonNull Canvas canvas);
+
+  void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder);
+
+  void setLayout(int width, int height, int left, int right, int top, int bottom, Point offset);
+
+  void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset);
+
+  @NonNull
+  Point getLocInFlatContainer();
+
+  @Nullable
+  BorderDrawable getBackgroundAndBorder();
+
+  @NonNull
+  Rect getBorderBox();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/WidgetGroup.java b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/WidgetGroup.java
new file mode 100644
index 0000000..9d89e9d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/flat/widget/WidgetGroup.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.flat.widget;
+
+
+import android.graphics.Canvas;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+import org.apache.weex.ui.flat.FlatGUIContext;
+
+import java.util.LinkedList;
+import java.util.List;
+
+@RestrictTo(Scope.LIBRARY)
+public class WidgetGroup extends BaseWidget {
+
+  private List<Widget> mChildren = new LinkedList<>();
+
+  public WidgetGroup(@NonNull FlatGUIContext context) {
+    super(context);
+  }
+
+  public void replaceAll(@NonNull List<Widget> widgets) {
+    mChildren = widgets;
+    invalidate();
+  }
+
+  public List<Widget> getChildren() {
+    return mChildren;
+  }
+
+  @Override
+  public void onDraw(@NonNull Canvas canvas) {
+    for (Widget child : mChildren) {
+      child.draw(canvas);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/ConsoleLogModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/ConsoleLogModule.java
new file mode 100644
index 0000000..ff1b594
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/ConsoleLogModule.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.utils.LogLevel;
+import java.util.Map;
+
+
+public class ConsoleLogModule extends WXModule {
+
+  @JSMethod(uiThread = false)
+  public void switchLogLevel(@Nullable String logLevel, @Nullable JSCallback callback) {
+    LogLevel logLevelEnum = getLogLevel(logLevel);
+    Map<String, String> ret = new ArrayMap<>();
+    if (logLevelEnum != null) {
+      WXEnvironment.sLogLevel = logLevelEnum;
+      WXBridgeManager.getInstance().setLogLevel(WXEnvironment.sLogLevel.getValue(),WXEnvironment.isPerf());
+      ret.put("status", "success");
+    } else {
+      ret.put("status", "failure");
+    }
+
+    if (callback != null) {
+      callback.invoke(ret);
+    }
+
+  }
+
+  @JSMethod(uiThread = false)
+  public void setPerfMode(@Nullable String on) {
+    WXEnvironment.isPerf = "true".equals(on);
+    WXBridgeManager.getInstance().setLogLevel(WXEnvironment.sLogLevel.getValue(),WXEnvironment.isPerf());
+  }
+
+  private @Nullable LogLevel getLogLevel(@Nullable String logLevel) {
+    LogLevel logLevelEnum = null;
+    if(!TextUtils.isEmpty(logLevel)){
+      switch (logLevel){
+        case "off":
+          logLevelEnum = LogLevel.OFF;
+          break;
+        case "error":
+          logLevelEnum = LogLevel.ERROR;
+          break;
+        case "warning":
+          logLevelEnum = LogLevel.WARN;
+          break;
+        case "info":
+          logLevelEnum = LogLevel.INFO;
+          break;
+        case "debug":
+          logLevelEnum = LogLevel.DEBUG;
+          break;
+      }
+    }
+    return logLevelEnum;
+  }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/WXDeviceInfoModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/WXDeviceInfoModule.java
new file mode 100644
index 0000000..243a8ce
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/WXDeviceInfoModule.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.util.HashMap;
+
+public class WXDeviceInfoModule extends WXModule {
+    
+    @JSMethod(uiThread = false)
+    public void enableFullScreenHeight(final JSCallback callback,JSONObject extend){
+        if(mWXSDKInstance != null) {
+            mWXSDKInstance.setEnableFullScreenHeight(true);
+            if(callback != null) {
+                long fullScreenHeight = WXViewUtils.getScreenHeight(mWXSDKInstance.getInstanceId());
+                HashMap<String, String> ret = new HashMap();
+                ret.put("fullScreenHeight", String.valueOf(fullScreenHeight));
+                callback.invoke(ret);
+            }
+
+        }
+
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/WXDomModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/WXDomModule.java
new file mode 100644
index 0000000..11e5a36
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/WXDomModule.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.dom.binding.JSONUtils;
+import org.apache.weex.ui.action.ActionAddRule;
+import org.apache.weex.ui.action.ActionGetComponentRect;
+import org.apache.weex.ui.action.ActionGetLayoutDirection;
+import org.apache.weex.ui.action.ActionInvokeMethod;
+import org.apache.weex.ui.action.GraphicActionBatchBegin;
+import org.apache.weex.ui.action.GraphicActionBatchEnd;
+import org.apache.weex.ui.action.GraphicActionScrollToElement;
+import org.apache.weex.ui.action.UpdateComponentDataAction;
+import org.apache.weex.utils.WXLogUtils;
+
+/**
+ * <p>
+ * Module class for dom operation.
+ * </p>
+ * <p>
+ *   This module is work different with other regular module, method is invoked directly, without reflection.
+ * </p>
+ *
+ * <p>
+ *  This class is for internal purpose,
+ *  please don't use it directly unless you know what you are doing.
+ * </p>
+ */
+@RestrictTo(Scope.LIBRARY_GROUP)
+public class WXDomModule extends WXModule {
+
+  /** package **/
+  public static final String SCROLL_TO_ELEMENT = "scrollToElement";
+  public static final String ADD_RULE = "addRule";
+  public static final String GET_COMPONENT_RECT = "getComponentRect";
+  public static final String GET_COMPONENT_DIRECTION = "getLayoutDirection";
+  public static final String WXDOM = "dom";
+  public static final String INVOKE_METHOD = "invokeMethod";
+
+  public static final String UPDATE_COMPONENT_DATA = "updateComponentData";
+
+  public static final String BATCH_BEGIN = "beginBatchMark";
+  public static final String BATCH_END = "endBatchMark";
+
+  /**
+   * Methods expose to js. Every method which will be called in js should add to this array.
+   */
+  public static final String[] METHODS = {SCROLL_TO_ELEMENT, ADD_RULE, GET_COMPONENT_RECT,
+      INVOKE_METHOD, GET_COMPONENT_DIRECTION, BATCH_BEGIN, BATCH_END};
+
+  public WXDomModule(WXSDKInstance instance){
+    mWXSDKInstance = instance;
+  }
+
+  public void callDomMethod(JSONObject task, long... parseNanos) {
+    if (task == null) {
+      return;
+    }
+    String method = (String) task.get(WXBridgeManager.METHOD);
+    JSONArray args = (JSONArray) task.get(WXBridgeManager.ARGS);
+    callDomMethod(method,args,parseNanos);
+  }
+
+  public Object callDomMethod(String method, JSONArray args, long... parseNanos) {
+
+    if (method == null) {
+      return null;
+    }
+
+    try {
+      switch (method) {
+        case GET_COMPONENT_DIRECTION: {
+          if(args == null){
+            return null;
+          }
+          new ActionGetLayoutDirection(mWXSDKInstance, args.getString(0), args.getString(1))
+                  .executeActionOnRender();
+          break;
+        }
+        case SCROLL_TO_ELEMENT:{
+          if (args == null) {
+            return null;
+          }
+          String ref = args.size() >= 1 ? args.getString(0) : null;
+          JSONObject options = args.size() >= 2 ? args.getJSONObject(1) : null;
+          new GraphicActionScrollToElement(mWXSDKInstance, ref, options)
+                  .executeActionOnRender();
+          break;
+        }
+        case ADD_RULE:{
+          if (args == null) {
+            return null;
+          }
+          new ActionAddRule(mWXSDKInstance.getInstanceId(), args.getString(0), args.getJSONObject(1))
+                  .executeAction();
+          break;
+        }
+        case GET_COMPONENT_RECT:{
+            if(args == null){
+                return null;
+            }
+            new ActionGetComponentRect(mWXSDKInstance, args.getString(0), args.getString(1))
+                    .executeActionOnRender();
+            break;
+        }
+        case INVOKE_METHOD: {
+          if(args == null){
+            return null;
+          }
+          // todo:no sure where the request com from
+          new ActionInvokeMethod(mWXSDKInstance.getInstanceId(), args.getString(0), args.getString(1), args.getJSONArray(2))
+                  .executeAction();
+          break;
+        }
+        case UPDATE_COMPONENT_DATA:
+          if(args == null || args.size() < 3){
+            return null;
+          }
+          new UpdateComponentDataAction(mWXSDKInstance, args.getString(0), JSONUtils.toJSON(args.get(1)), args.getString(2)).executeAction();
+          break;
+        case BATCH_BEGIN: {
+          if(args == null){
+            return null;
+          }
+          String ref = args.size() >= 1 ? args.getString(0) : null;
+          new GraphicActionBatchBegin(mWXSDKInstance, ref).executeActionOnRender();
+          break;
+        }
+        case BATCH_END: {
+          String ref = args.size() >= 1 ? args.getString(0) : null;
+          new GraphicActionBatchEnd(mWXSDKInstance, ref).executeActionOnRender();
+          break;
+        }
+        default:
+          WXLogUtils.e("Unknown dom action.");
+          break;
+      }
+
+      // todo TraceableAction
+//      if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+//        String ref = null;
+//        String type = null;
+//        if (args.size() > 0) {
+//          if (args.size() >= 1) {
+//            if (args.get(0) instanceof String) {
+//              ref = args.getString(0);
+//            } else if (args.get(0) instanceof JSONObject) {
+//              ref = ((JSONObject) args.get(0)).getString("ref");
+//              type = ((JSONObject) args.get(0)).getString("type");
+//            }
+//          }
+//
+//          if (args.size() >= 2) {
+//            if (args.get(1) instanceof JSONObject) {
+//              ref = ((JSONObject) args.get(1)).getString("ref");
+//              type = ((JSONObject) args.get(1)).getString("type");
+//            }
+//          }
+//        }
+//        if (parseNanos != null && parseNanos.length == 1) {
+//          ((TraceableAction) action).mParseJsonNanos = parseNanos[0];
+//          ((TraceableAction) action).mStartMillis -= Stopwatch.nanosToMillis(parseNanos[0]);
+//        }
+//        ((TraceableAction) action).onStartDomExecute(mWXSDKInstance.getInstanceId(), method, ref, type, args.toJSONString());
+//      }
+    } catch (IndexOutOfBoundsException e) {
+      // no enougn args
+      e.printStackTrace();
+      WXLogUtils.e("Dom module call miss arguments.");
+    } catch (ClassCastException cce) {
+      WXLogUtils.e("Dom module call arguments format error!!");
+    }
+    return null;
+  }
+
+  public void invokeMethod(String ref, String method, JSONArray args){
+    if(ref == null || method == null){
+      return;
+    }
+
+    new ActionInvokeMethod(mWXSDKInstance.getInstanceId(), ref, method, args)
+            .executeAction();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/WXLocaleModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/WXLocaleModule.java
new file mode 100644
index 0000000..63cf9c2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/WXLocaleModule.java
@@ -0,0 +1,112 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.LocaleList;
+import android.text.TextUtils;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.common.WXModule;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Created by moxun on 2017/9/26.
+ * <p>
+ * Ref: https://tools.ietf.org/html/bcp47
+ */
+
+public class WXLocaleModule extends WXModule {
+
+  @JSMethod(uiThread = false)
+  public String getLanguageSync() {
+    return getLanguageImpl();
+  }
+
+  @JSMethod(uiThread = false)
+  public void getLanguage(JSCallback callback) {
+    callback.invoke(getLanguageImpl());
+  }
+
+  private String getLanguageImpl() {
+    Locale locale;
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+      locale = LocaleList.getDefault().get(0);
+    } else locale = Locale.getDefault();
+
+    String language = locale.getLanguage() + "-" + locale.getCountry();
+    return language;
+  }
+
+  @JSMethod(uiThread = false)
+  public List<String> getLanguages() {
+    String[] tags = getLanguageTags().split(",");
+    return Arrays.asList(tags);
+  }
+
+  @JSMethod(uiThread = false)
+  public void getLanguages(JSCallback callback) {
+    callback.invoke(getLanguageTags().split(","));
+  }
+
+  private String getLanguageTags() {
+    Context application = WXEnvironment.getApplication();
+    if (application != null) {
+      Resources res = application.getResources();
+      if (res != null) {
+        Configuration configuration = res.getConfiguration();
+        if (configuration != null) {
+          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            LocaleList localeList = configuration.getLocales();
+            return localeList.toLanguageTags();
+          } else {
+            Locale local = configuration.locale;
+            if (local != null) {
+              return toLanguageTag(local);
+            }
+          }
+        }
+      }
+    }
+    return "";
+  }
+
+  private String toLanguageTag(Locale locale) {
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+      return locale.toLanguageTag();
+    } else {
+      StringBuilder sb = new StringBuilder();
+      String language = locale.getLanguage();
+      String region = locale.getCountry();
+      sb.append(language);
+      if (!TextUtils.isEmpty(region)) {
+        sb.append("-").append(region);
+      }
+      return sb.toString();
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/WXMetaModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/WXMetaModule.java
new file mode 100644
index 0000000..5911229
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/WXMetaModule.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by zhengshihan on 16/12/20.
+ */
+
+public class WXMetaModule extends WXModule {
+
+    public static final String WIDTH = "width";
+    public static final String DEVICE_WIDTH = "device-width";
+
+    @JSMethod(uiThread = false)
+    public void setViewport(String param) {
+        if (!TextUtils.isEmpty(param)) {
+            try {
+                param = URLDecoder.decode(param, "utf-8");
+                JSONObject jsObj = JSON.parseObject(param);
+                Context cxt = mWXSDKInstance.getContext();
+                // todo maybe getString(WIDTH) is "device-height"
+                if (DEVICE_WIDTH.endsWith(jsObj.getString(WIDTH))) {
+                    int width = (int)(WXViewUtils.getScreenWidth(cxt)/WXViewUtils.getScreenDensity(cxt));
+                    mWXSDKInstance.setInstanceViewPortWidth(width,true);
+                    WXLogUtils.d("[WXMetaModule] setViewport success[device-width]=" + width);
+                } else {
+                    int width = jsObj.getInteger(WIDTH);
+                    if (width > 0) {
+                        mWXSDKInstance.setInstanceViewPortWidth(width,true);
+                    }
+                    WXLogUtils.d("[WXMetaModule] setViewport success[width]=" + width);
+                }
+            } catch (Exception e) {
+                WXLogUtils.e("[WXMetaModule] alert param parse error ", e);
+            }
+        }
+    }
+
+    @JSMethod(uiThread = true)
+    public void openLog(String open) {
+        Application application = WXEnvironment.getApplication();
+        if(application == null){
+            return;
+        }
+        ApplicationInfo info = application.getApplicationInfo();
+        if((info.flags & ApplicationInfo.FLAG_DEBUGGABLE)!= 0){
+            if(WXUtils.getBoolean(open, true)) {
+                WXEnvironment.setApkDebugable(true);
+                if(mWXSDKInstance != null) {
+                    Toast.makeText(mWXSDKInstance.getContext(), "log open success", Toast.LENGTH_SHORT).show();
+                }
+            }else{
+                WXEnvironment.setApkDebugable(false);
+                if(mWXSDKInstance != null) {
+                    Toast.makeText(mWXSDKInstance.getContext(), "log close success", Toast.LENGTH_SHORT).show();
+                }
+            }
+        }
+    }
+
+    @JSMethod(uiThread = false)
+    public void getPageInfo(JSCallback callback) {
+        if(callback == null){
+            return;
+        }
+        List<WXSDKInstance> instances = WXSDKManager.getInstance().getWXRenderManager().getAllInstances();
+        Map<String,Object> map = new HashMap<>(4);
+        for(WXSDKInstance instance : instances){
+            if(TextUtils.isEmpty(instance.getBundleUrl())){
+                continue;
+            }
+            map.put(instance.getBundleUrl(), instance.getTemplateInfo());
+        }
+        callback.invoke(map);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/WXModalUIModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/WXModalUIModule.java
new file mode 100644
index 0000000..bbd0574
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/WXModalUIModule.java
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.widget.EditText;
+import android.widget.Toast;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.JSCallback;
+import org.apache.weex.utils.WXLogUtils;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.weex.WXSDKEngine.DestroyableModule;
+
+
+/**
+ * WXModalUIModule module provide toast、alert、confirm、prompt to display the message.
+ * for example(weex JS):
+ * this.$call('modal','toast',{'message':'test toast','duration': 2.0});
+ */
+public class WXModalUIModule extends DestroyableModule {
+
+  public static final String OK = "OK";
+  public static final String CANCEL = "Cancel";
+  public static final String RESULT = "result";
+  public static final String DATA = "data";
+  public static final String MESSAGE = "message";
+  public static final String DURATION = "duration";
+  public static final String OK_TITLE = "okTitle";
+  public static final String CANCEL_TITLE = "cancelTitle";
+  public static final String DEFAULT = "default";
+  private Toast toast;
+  private Dialog activeDialog;
+
+  @SuppressLint("ShowToast")
+  @JSMethod(uiThread = true)
+  public void toast(JSONObject jsObj) {
+    if(mWXSDKInstance.getContext() == null){
+      return;
+    }
+    String message = "";
+    int duration = Toast.LENGTH_SHORT;
+    if (jsObj != null) {
+      try {
+        message = jsObj.getString(MESSAGE);
+        if(jsObj.containsKey(DURATION)) {
+          duration = jsObj.getInteger(DURATION);
+        }
+      } catch (Exception e) {
+        WXLogUtils.e("[WXModalUIModule] alert param parse error ", e);
+      }
+    }
+    if (TextUtils.isEmpty(message)) {
+      WXLogUtils.e("[WXModalUIModule] toast param parse is null ");
+      return;
+    }
+
+    if (duration > 3) {
+      duration = Toast.LENGTH_LONG;
+    } else {
+      duration = Toast.LENGTH_SHORT;
+    }
+    if (toast == null) {
+      toast = Toast.makeText(mWXSDKInstance.getContext(), message, duration);
+    } else {
+      toast.setDuration(duration);
+      toast.setText(message);
+    }
+    toast.setGravity(Gravity.CENTER, 0, 0);
+    toast.show();
+  }
+
+  @JSMethod(uiThread = true)
+  public void alert(JSONObject jsObj, final JSCallback callback) {
+
+    if (mWXSDKInstance.getContext() instanceof Activity) {
+
+      String message = "";
+      String okTitle = OK;
+      if (jsObj != null) {
+        try {
+          message = jsObj.getString(MESSAGE);
+          okTitle = jsObj.getString(OK_TITLE);
+        } catch (Exception e) {
+          WXLogUtils.e("[WXModalUIModule] alert param parse error ", e);
+        }
+      }
+      if (TextUtils.isEmpty(message)) {
+        message = "";
+      }
+      AlertDialog.Builder builder = new AlertDialog.Builder(mWXSDKInstance.getContext());
+      builder.setMessage(message);
+
+      final String okTitle_f = TextUtils.isEmpty(okTitle) ? OK : okTitle;
+      builder.setPositiveButton(okTitle_f, new OnClickListener() {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+          if (callback != null) {
+            callback.invoke(okTitle_f);
+          }
+        }
+      });
+      AlertDialog alertDialog = builder.create();
+      alertDialog.setCanceledOnTouchOutside(false);
+      alertDialog.show();
+      tracking(alertDialog);
+    } else {
+      WXLogUtils.e("[WXModalUIModule] when call alert mWXSDKInstance.getContext() must instanceof Activity");
+    }
+  }
+
+  @JSMethod(uiThread = true)
+  public void confirm(JSONObject jsObj, final JSCallback callback) {
+
+    if (mWXSDKInstance.getContext() instanceof Activity) {
+      String message = "";
+      String okTitle = OK;
+      String cancelTitle = CANCEL;
+
+      if (jsObj != null) {
+        try {
+          message = jsObj.getString(MESSAGE);
+          okTitle = jsObj.getString(OK_TITLE);
+          cancelTitle = jsObj.getString(CANCEL_TITLE);
+        } catch (Exception e) {
+          WXLogUtils.e("[WXModalUIModule] confirm param parse error ", e);
+        }
+      }
+      if (TextUtils.isEmpty(message)) {
+        message = "";
+      }
+      AlertDialog.Builder builder = new AlertDialog.Builder(mWXSDKInstance.getContext());
+      builder.setMessage(message);
+
+      final String okTitleFinal = TextUtils.isEmpty(okTitle) ? OK : okTitle;
+      final String cancelTitleFinal = TextUtils.isEmpty(cancelTitle) ? CANCEL : cancelTitle;
+
+      builder.setPositiveButton(okTitleFinal, new OnClickListener() {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+          if (callback != null) {
+            callback.invoke(okTitleFinal);
+          }
+        }
+      });
+      builder.setNegativeButton(cancelTitleFinal, new OnClickListener() {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+          if (callback != null) {
+            callback.invoke(cancelTitleFinal);
+          }
+        }
+      });
+      AlertDialog alertDialog = builder.create();
+      alertDialog.setCanceledOnTouchOutside(false);
+      alertDialog.show();
+      tracking(alertDialog);
+    } else {
+      WXLogUtils.e("[WXModalUIModule] when call confirm mWXSDKInstance.getContext() must instanceof Activity");
+    }
+  }
+
+  @JSMethod(uiThread = true)
+  public void prompt(JSONObject jsObj, final JSCallback callback) {
+    if (mWXSDKInstance.getContext() instanceof Activity) {
+      String message = "";
+      String defaultValue = "";
+      String okTitle = OK;
+      String cancelTitle = CANCEL;
+
+      if (jsObj != null) {
+        try {
+          message = jsObj.getString(MESSAGE);
+          okTitle = jsObj.getString(OK_TITLE);
+          cancelTitle = jsObj.getString(CANCEL_TITLE);
+          defaultValue = jsObj.getString(DEFAULT);
+        } catch (Exception e) {
+          WXLogUtils.e("[WXModalUIModule] confirm param parse error ", e);
+        }
+      }
+
+      if (TextUtils.isEmpty(message)) {
+        message = "";
+      }
+      AlertDialog.Builder builder = new AlertDialog.Builder(mWXSDKInstance.getContext());
+      builder.setMessage(message);
+
+      final EditText editText = new EditText(mWXSDKInstance.getContext());
+      editText.setText(defaultValue);
+      builder.setView(editText);
+      final String okTitleFinal = TextUtils.isEmpty(okTitle) ? OK : okTitle;
+      final String cancelTitleFinal = TextUtils.isEmpty(cancelTitle) ? CANCEL : cancelTitle;
+      builder.setPositiveButton(okTitleFinal, new OnClickListener() {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+          if (callback != null) {
+            Map<String, Object> result = new HashMap<String, Object>();
+            result.put(RESULT, okTitleFinal);
+            result.put(DATA, editText.getText().toString());
+            callback.invoke(result);
+          }
+        }
+      }).setNegativeButton(cancelTitleFinal, new OnClickListener() {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+          if (callback != null) {
+            Map<String, Object> result = new HashMap<String, Object>();
+            result.put(RESULT, cancelTitleFinal);
+            result.put(DATA, editText.getText().toString());
+            callback.invoke(result);
+          }
+
+        }
+      });
+      AlertDialog alertDialog = builder.create();
+      alertDialog.setCanceledOnTouchOutside(false);
+      alertDialog.show();
+      tracking(alertDialog);
+    } else {
+      WXLogUtils.e("when call prompt mWXSDKInstance.getContext() must instanceof Activity");
+    }
+  }
+
+  private void tracking(Dialog dialog) {
+    activeDialog = dialog;
+    dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+      @Override
+      public void onDismiss(DialogInterface dialog) {
+        activeDialog = null;
+      }
+    });
+  }
+
+  @Override
+  public void destroy() {
+    if (activeDialog != null && activeDialog.isShowing()) {
+      activeDialog.dismiss();
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/WXTimerModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/WXTimerModule.java
new file mode 100644
index 0000000..f0d419f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/WXTimerModule.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import android.annotation.SuppressLint;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.VisibleForTesting;
+import android.util.SparseArray;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.bridge.WXHashMap;
+import org.apache.weex.bridge.WXJSObject;
+import org.apache.weex.common.Destroyable;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.utils.WXJsonUtils;
+import org.apache.weex.utils.WXLogUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.common.WXJSBridgeMsgType;
+
+public class WXTimerModule extends WXModule implements Destroyable, Handler.Callback {
+
+  @IntDef({WXJSBridgeMsgType.MODULE_TIMEOUT, WXJSBridgeMsgType.MODULE_INTERVAL})
+  @Retention(RetentionPolicy.SOURCE)
+  @interface MessageType {}
+
+  private final static String TAG = "timer";
+  private Handler handler;
+  private SparseArray<Integer> antiIntAutoBoxing;
+
+  @SuppressLint("UseSparseArrays")
+  public WXTimerModule() {
+    handler = new Handler(WXBridgeManager.getInstance().getJSLooper(), this);
+    antiIntAutoBoxing = new SparseArray<>();
+  }
+
+
+  @JSMethod(uiThread = false)
+  public void setTimeout(@IntRange(from = 1) int funcId, @FloatRange(from = 0) float delay) {
+    if(mWXSDKInstance != null) {
+      postOrHoldMessage(WXJSBridgeMsgType.MODULE_TIMEOUT, funcId, (int) delay, WXUtils.parseInt(mWXSDKInstance.getInstanceId()));
+      if (null != mWXSDKInstance.getWXPerformance()){
+        mWXSDKInstance.getWXPerformance().timerInvokeCount++;
+      }
+      mWXSDKInstance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_TIMER_NUM,1);
+    }
+  }
+
+  @JSMethod(uiThread = false)
+  public void setInterval(@IntRange(from = 1) int funcId, @FloatRange(from = 0) float interval) {
+    if(mWXSDKInstance != null) {
+      postOrHoldMessage(WXJSBridgeMsgType.MODULE_INTERVAL, funcId, (int) interval, WXUtils.parseInt(mWXSDKInstance.getInstanceId()));
+      if (null != mWXSDKInstance.getWXPerformance()){
+        mWXSDKInstance.getWXPerformance().timerInvokeCount++;
+      }
+      mWXSDKInstance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_TIMER_NUM,1);
+    }
+  }
+
+  @JSMethod(uiThread = false)
+  public void clearTimeout(@IntRange(from = 1) int funcId) {
+    if (funcId <= 0) {
+      return;
+    }
+    removeOrHoldMessage(WXJSBridgeMsgType.MODULE_TIMEOUT, funcId);
+  }
+
+  @JSMethod(uiThread = false)
+  public void clearInterval(@IntRange(from = 1) int funcId) {
+    if (funcId <= 0) {
+      return;
+    }
+    removeOrHoldMessage(WXJSBridgeMsgType.MODULE_INTERVAL, funcId);
+  }
+
+  @Override
+  public void destroy() {
+    if (handler != null) {
+      if(WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d(TAG, "Timer Module removeAllMessages: ");
+      }
+      handler.removeCallbacksAndMessages(null);
+      antiIntAutoBoxing.clear();
+    }
+  }
+
+  @Override
+  public boolean handleMessage(Message msg) {
+    boolean ret = false;
+    WXJSObject[] args;
+    if (msg != null) {
+      int what = msg.what;
+      if(WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d(TAG, "Timer Module handleMessage : " + msg.what);
+      }
+      switch (what) {
+        case WXJSBridgeMsgType.MODULE_TIMEOUT:
+          if (msg.obj == null) {
+            break;
+          }
+          checkIfTimerInBack(msg.arg1);
+          args = createTimerArgs(msg.arg1, (Integer) msg.obj, false);
+          WXBridgeManager.getInstance().invokeExecJS(String.valueOf(msg.arg1), null, WXBridgeManager.METHOD_CALL_JS, args, true);
+          ret = true;
+          break;
+        case WXJSBridgeMsgType.MODULE_INTERVAL:
+          if (msg.obj == null) {
+            break;
+          }
+          checkIfTimerInBack(msg.arg1);
+          postMessage(WXJSBridgeMsgType.MODULE_INTERVAL, (Integer) msg.obj, msg.arg2, msg.arg1);
+          args = createTimerArgs(msg.arg1, (Integer) msg.obj, true);
+          WXBridgeManager.getInstance().invokeExecJS(String.valueOf(msg.arg1), null, WXBridgeManager.METHOD_CALL_JS, args, true);
+          ret = true;
+          break;
+        default:
+          break;
+      }
+    }
+    return ret;
+  }
+
+  private void checkIfTimerInBack(int instanceId){
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(String.valueOf(instanceId));
+    if (null == instance){
+      return;
+    }
+    if (instance.isViewDisAppear()){
+      instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_TIMER_BACK_NUM,1);
+    }
+  }
+
+  @VisibleForTesting
+  void setHandler(Handler handler) {
+    this.handler = handler;
+  }
+
+  private WXJSObject[] createTimerArgs(int instanceId, int funcId, boolean keepAlive) {
+    ArrayList<Object> argsList = new ArrayList<>();
+    argsList.add(funcId);
+    argsList.add(new HashMap<>());
+    argsList.add(keepAlive);
+    WXHashMap<String, Object> task = new WXHashMap<>();
+    task.put(WXBridgeManager.KEY_METHOD, WXBridgeManager.METHOD_CALLBACK);
+    task.put(WXBridgeManager.KEY_ARGS, argsList);
+    Object[] tasks = {task};
+    return new WXJSObject[]{
+            new WXJSObject(WXJSObject.String, String.valueOf(instanceId)),
+            new WXJSObject(WXJSObject.JSON,
+                    WXJsonUtils.fromObjectToJSONString(tasks))};
+  }
+
+  private void postOrHoldMessage(@MessageType final int what,final int funcId,final int interval,final int instanceId) {
+    if(mWXSDKInstance.isPreRenderMode()) {
+      postMessage(what,funcId,interval,instanceId);
+    } else {
+      postMessage(what,funcId,interval,instanceId);
+    }
+  }
+
+  private void removeOrHoldMessage(@MessageType final int what,final int funcId) {
+    if(mWXSDKInstance.isPreRenderMode()) {
+      handler.removeMessages(what, antiIntAutoBoxing.get(funcId, funcId));
+    } else {
+      handler.removeMessages(what, antiIntAutoBoxing.get(funcId, funcId));
+    }
+  }
+
+  private void postMessage(@MessageType int what,
+                           @IntRange(from = 1) int funcId,
+                           @IntRange(from = 0) int interval, int instanceId) {
+    if (interval < 0 || funcId <= 0) {
+      WXLogUtils.e(TAG, "interval < 0 or funcId <=0");
+    } else {
+      if(antiIntAutoBoxing.get(funcId) == null) {
+        antiIntAutoBoxing.put(funcId, funcId);
+      }
+      Message message = handler
+              .obtainMessage(what, instanceId, interval, antiIntAutoBoxing.get(funcId));
+      handler.sendMessageDelayed(message, interval);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/module/WXWebViewModule.java b/android/sdk/src/main/java/org/apache/weex/ui/module/WXWebViewModule.java
new file mode 100644
index 0000000..2513d36
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/module/WXWebViewModule.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.module;
+
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.annotation.JSMethod;
+import org.apache.weex.common.WXModule;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXWeb;
+
+public class WXWebViewModule extends WXModule {
+
+    private enum Action {
+        reload,
+        goBack,
+        goForward,
+        postMessage
+    }
+
+    @JSMethod(uiThread = true)
+    public void goBack(String ref) {
+        action(Action.goBack, ref);
+    }
+
+    @JSMethod(uiThread = true)
+    public void goForward(String ref) {
+        action(Action.goForward, ref);
+    }
+
+    @JSMethod(uiThread = true)
+    public void reload(String ref) {
+        action(Action.reload, ref);
+    }
+
+    @JSMethod(uiThread = true)
+    public void postMessage(String ref, Object msg) {
+        action(Action.postMessage, ref, msg);
+    }
+
+    private void action(Action action, String ref, Object data) {
+        WXComponent webComponent =
+            WXSDKManager.getInstance()
+                .getWXRenderManager()
+                .getWXComponent(mWXSDKInstance.getInstanceId(), ref);
+        if(webComponent instanceof WXWeb) {
+            ((WXWeb) webComponent).setAction(action.name(), data);
+        }
+    }
+
+    private void action(Action action, String ref) {
+        action(action, ref, null);
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/BaseFrameLayout.java b/android/sdk/src/main/java/org/apache/weex/ui/view/BaseFrameLayout.java
new file mode 100644
index 0000000..8c008f7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/BaseFrameLayout.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.widget.FrameLayout;
+import org.apache.weex.ui.flat.widget.Widget;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXViewUtils;
+import java.util.List;
+
+public class BaseFrameLayout extends FrameLayout{
+    private List<Widget> mWidgets;
+
+    public BaseFrameLayout(Context context){
+        super(context);
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        try {
+            dispatchDrawInterval(canvas);
+        } catch (Throwable e) {
+            WXLogUtils.e(WXLogUtils.getStackTrace(e));
+        }
+    }
+
+    protected void dispatchDrawInterval(Canvas canvas) {
+        if (mWidgets != null) {
+            canvas.save();
+            canvas.translate(getPaddingLeft(), getPaddingTop());
+            for (Widget widget : mWidgets) {
+                widget.draw(canvas);
+            }
+            canvas.restore();
+        } else {
+            WXViewUtils.clipCanvasWithinBorderBox(this, canvas);
+            super.dispatchDraw(canvas);
+        }
+    }
+    public void mountFlatGUI(List<Widget> widgets){
+        this.mWidgets = widgets;
+        if (mWidgets != null) {
+            setWillNotDraw(true);
+        }
+        invalidate();
+    }
+
+    public void unmountFlatGUI(){
+        mWidgets = null;
+        setWillNotDraw(false);
+        invalidate();
+    }
+
+    @Override
+    protected boolean verifyDrawable(@NonNull Drawable who) {
+        return mWidgets != null || super.verifyDrawable(who);
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/IRenderResult.java b/android/sdk/src/main/java/org/apache/weex/ui/view/IRenderResult.java
new file mode 100644
index 0000000..fc46fe9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/IRenderResult.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+
+import org.apache.weex.ui.component.WXComponent;
+
+public interface IRenderResult<T extends WXComponent> {
+    T getComponent();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/IRenderStatus.java b/android/sdk/src/main/java/org/apache/weex/ui/view/IRenderStatus.java
new file mode 100644
index 0000000..ae7effe
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/IRenderStatus.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+
+import org.apache.weex.ui.component.WXComponent;
+
+public interface IRenderStatus<T extends WXComponent> {
+
+  public void holdComponent(T component);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/IWXScroller.java b/android/sdk/src/main/java/org/apache/weex/ui/view/IWXScroller.java
new file mode 100644
index 0000000..a2c8314
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/IWXScroller.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+public interface IWXScroller {
+
+  void destroy();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/IWXTextView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/IWXTextView.java
new file mode 100644
index 0000000..da71307
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/IWXTextView.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+public interface IWXTextView {
+
+  CharSequence getText();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/IWebView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/IWebView.java
new file mode 100644
index 0000000..7a0f8a8
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/IWebView.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.view.View;
+
+import java.util.Map;
+
+public interface IWebView {
+    public View getView();
+    public void destroy();
+    public void loadUrl(String url);
+    public void loadDataWithBaseURL(String source);
+    public void reload();
+    public void goBack();
+    public void goForward();
+    public void postMessage(Object msg);
+    public void setShowLoading(boolean shown);
+    public void setOnErrorListener(OnErrorListener listener);
+    public void setOnPageListener(OnPageListener listener);
+    public void setOnMessageListener(OnMessageListener listener);
+
+    public interface OnErrorListener {
+        public void onError(String type, Object message);
+    }
+
+    public interface OnPageListener {
+        public void onReceivedTitle(String title);
+        public void onPageStart(String url);
+        public void onPageFinish(String url, boolean canGoBack, boolean canGoForward);
+    }
+
+    public interface OnMessageListener {
+        public void onMessage(Map<String, Object> params);
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXBaseCircleIndicator.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXBaseCircleIndicator.java
new file mode 100644
index 0000000..070fda4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXBaseCircleIndicator.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.support.v4.view.ViewPager;
+import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.utils.WXViewUtils;
+
+
+public class WXBaseCircleIndicator extends FrameLayout implements WXGestureObservable {
+
+  private final Paint mPaintPage = new Paint();
+  private final Paint mPaintFill = new Paint();
+  private WXGesture wxGesture;
+  private WXCircleViewPager mCircleViewPager;
+
+  /**
+   * Radius of the circle
+   */
+  private float radius;
+  /**
+   * Padding of the circle
+   */
+  private float circlePadding;
+  /**
+   * Fill color of unselected circle
+   */
+  private int pageColor = Color.LTGRAY;
+  /**
+   * Fill color of the selected circle
+   */
+  private int fillColor = Color.DKGRAY;
+  private int realCurrentItem;
+
+  private OnPageChangeListener mListener;
+
+
+  public WXBaseCircleIndicator(Context context) {
+    super(context);
+    init();
+  }
+
+  private void init() {
+    radius = WXViewUtils.dip2px(5);
+    circlePadding = WXViewUtils.dip2px(5);
+    pageColor = Color.LTGRAY;
+    fillColor = Color.DKGRAY;
+
+    mPaintFill.setStyle(Style.FILL);
+    mPaintFill.setAntiAlias(true);
+    mPaintPage.setAntiAlias(true);
+    mPaintPage.setColor(pageColor);
+    mPaintFill.setStyle(Style.FILL);
+    mPaintFill.setColor(fillColor);
+    this.setWillNotDraw(false);
+
+  }
+
+  /**
+   * @param context
+   * @param attrs
+   */
+  public WXBaseCircleIndicator(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    init();
+  }
+
+  /**
+   * @param viewPager the mCircleViewPager to set
+   */
+  public void setCircleViewPager(WXCircleViewPager viewPager) {
+    mCircleViewPager = viewPager;
+    if (mCircleViewPager != null) {
+      if (mListener == null) {
+        mListener = new ViewPager.SimpleOnPageChangeListener() {
+          @Override
+          public void onPageSelected(int position) {
+            realCurrentItem = mCircleViewPager.getRealCurrentItem();
+            invalidate();
+          }
+        };
+      }
+      this.mCircleViewPager.addOnPageChangeListener(mListener);
+      this.realCurrentItem = mCircleViewPager.getRealCurrentItem();
+      if (realCurrentItem < 0) {
+        realCurrentItem = 0;
+      }
+    }
+    requestLayout();
+  }
+
+  /**
+   * @param radius the radius to set
+   */
+  public void setRadius(float radius) {
+    this.radius = radius;
+  }
+
+  /**
+   * @param fillColor the fillColor to set
+   */
+  public void setFillColor(int fillColor) {
+    this.fillColor = fillColor;
+    mPaintFill.setColor(fillColor);
+  }
+
+  public void setPageColor(int pageColor) {
+    this.pageColor = pageColor;
+    mPaintPage.setColor(pageColor);
+  }
+
+  /**
+   * @return the realCurrentItem
+   */
+  public int getRealCurrentItem() {
+    return realCurrentItem;
+  }
+
+  /**
+   * @param realCurrentItem the realCurrentItem to set
+   */
+  public void setRealCurrentItem(int realCurrentItem) {
+    this.realCurrentItem = realCurrentItem;
+    invalidate();
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(MotionEvent event) {
+    boolean result = super.dispatchTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+    return result;
+  }
+
+  @Override
+  protected void onDraw(Canvas canvas) {
+    super.onDraw(canvas);
+
+    float dotWidth = (circlePadding + radius) * 2;
+
+    float firstCenterX = getWidth() / 2 - (dotWidth * (getCount() - 1) / 2);
+    float firstCenterY = getHeight() / 2 + getPaddingTop();
+
+    for (int i = 0; i < getCount(); i++) {
+      float dx = firstCenterX + dotWidth * i;
+      float dy = firstCenterY;
+      if (i != realCurrentItem) {
+        canvas.drawCircle(dx, dy, radius, mPaintPage);
+      } else {
+        canvas.drawCircle(dx, dy, radius, mPaintFill);
+      }
+    }
+  }
+
+  @Override
+  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+
+    int viewWidth;
+    int viewHeight;
+
+    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+    if (widthMode == MeasureSpec.EXACTLY) {
+      viewWidth = widthSize;
+    } else {
+      viewWidth = (int) (getPaddingLeft() + radius * 2 * getCount() + circlePadding * (getCount() - 1) + getPaddingRight()) + 1;
+    }
+
+    if (heightMode == MeasureSpec.EXACTLY) {
+      viewHeight = heightSize;
+    } else {
+      viewHeight = (int) (getPaddingTop() + radius * 2 + getPaddingBottom()) + 1;
+    }
+    setMeasuredDimension(viewWidth, viewHeight);
+  }
+
+  /**
+   * @return the count
+   */
+  public int getCount() {
+    if (mCircleViewPager == null || mCircleViewPager.getAdapter() == null) {
+      return 0;
+    }
+    return mCircleViewPager.getRealCount();
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXBaseRefreshLayout.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXBaseRefreshLayout.java
new file mode 100644
index 0000000..5599581
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXBaseRefreshLayout.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.content.Context;
+
+public class WXBaseRefreshLayout extends WXFrameLayout {
+
+  public WXBaseRefreshLayout(Context context) {
+    super(context);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXCircleIndicator.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXCircleIndicator.java
new file mode 100644
index 0000000..4e73942
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXCircleIndicator.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.content.Context;
+
+public class WXCircleIndicator extends WXBaseCircleIndicator {
+
+  public WXCircleIndicator(Context context) {
+    super(context);
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXCirclePageAdapter.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXCirclePageAdapter.java
new file mode 100644
index 0000000..83edc06
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXCirclePageAdapter.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.support.v4.view.PagerAdapter;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class WXCirclePageAdapter extends PagerAdapter {
+
+  /**
+   * Subviews
+   */
+  private List<View> views = new ArrayList<>();
+  private List<View> shadow = new ArrayList<>();
+  private boolean needLoop = true;
+
+  public boolean isRTL = false;
+  private List<View> originalViews = new ArrayList<>();
+
+  public WXCirclePageAdapter(List<View> views, boolean needLoop) {
+    super();
+    this.views = new ArrayList<>(views);
+    this.originalViews = new ArrayList<>(views);
+    this.needLoop = needLoop;
+  }
+
+  public void setLayoutDirectionRTL(boolean isRTL) {
+    if (isRTL == this.isRTL) return;
+    this.isRTL = isRTL;
+    this.views = new ArrayList<>(this.originalViews);
+    if (isRTL) {
+      Collections.reverse(this.views);
+    }
+    ensureShadow();
+  }
+
+  public WXCirclePageAdapter() {
+    this(true);
+  }
+
+  public WXCirclePageAdapter(boolean needLoop) {
+    super();
+    this.needLoop = needLoop;
+  }
+
+  public void addPageView(View view) {
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("onPageSelected >>>> addPageView");
+    }
+
+    originalViews.add(view);
+    if (this.isRTL) {
+      views.add(0, view);
+    } else {
+      views.add(view);
+    }
+    ensureShadow();
+  }
+
+  public void removePageView(View view) {
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("onPageSelected >>>> removePageView");
+    }
+    views.remove(view);
+    originalViews.remove(view);
+    ensureShadow();
+  }
+
+  public void replacePageView(View oldView, View newView) {
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("onPageSelected >>>> replacePageView");
+    }
+
+    int index = views.indexOf(oldView);
+    views.remove(index);
+    views.add(index, newView);
+    ensureShadow();
+
+    index = originalViews.indexOf(oldView);
+    originalViews.remove(index);
+    originalViews.add(index, newView);
+  }
+
+  @Override
+  public int getCount() {
+    return shadow.size();
+  }
+
+  public int getRealCount() {
+    return views.size();
+  }
+
+  @Override
+  public Object instantiateItem(ViewGroup container, int position) {
+    View pageView = null;
+    try {
+      pageView = shadow.get(position);
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.d("onPageSelected >>>> instantiateItem >>>>> position:" + position + ",position % getRealCount()" + position % getRealCount());
+      }
+      if (pageView.getParent() == null) {
+        container.addView(pageView);
+      } else {
+        ((ViewGroup) pageView.getParent()).removeView(pageView);
+        container.addView(pageView);
+      }
+    } catch (Exception e) {
+      WXLogUtils.e("[CirclePageAdapter] instantiateItem: ", e);
+    }
+    return pageView;
+  }
+
+  @Override
+  public void destroyItem(ViewGroup container, int position, Object object) {
+    if (WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("onPageSelected >>>> destroyItem >>>>> position:" + position);
+    }
+    // container.removeView((View) object);
+  }
+
+  @Override
+  public boolean isViewFromObject(View view, Object object) {
+    return view == object;
+  }
+
+  @Override
+  public int getItemPosition(Object object) {
+    return POSITION_NONE;
+  }
+
+  public int getPagePosition(View page) {
+    return views.indexOf(page);
+  }
+
+  public int getItemIndex(Object object) {
+    if (object instanceof View) {
+      return views.indexOf(object);
+    } else {
+      return -1;
+    }
+  }
+
+  public List<View> getViews(){
+    return views;
+  }
+
+  private void ensureShadow() {
+    List<View> temp = new ArrayList<>();
+    if (needLoop && views.size() > 2) {
+      temp.add(0, views.get(views.size() - 1));
+      for (View view : views) {
+        temp.add(view);
+      }
+      temp.add(views.get(0));
+    } else {
+      temp.addAll(views);
+    }
+    shadow.clear();
+    notifyDataSetChanged();
+    shadow.addAll(temp);
+    notifyDataSetChanged();
+  }
+
+  public int getRealPosition(int shadowPosition) {
+    if (shadowPosition < 0 || shadowPosition >= shadow.size()) {
+      return -1;
+    } else {
+      return getItemIndex(shadow.get(shadowPosition));
+    }
+  }
+
+  public int getFirst() {
+    if (needLoop && views.size() > 2) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXCircleViewPager.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXCircleViewPager.java
new file mode 100644
index 0000000..65e8d8a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXCircleViewPager.java
@@ -0,0 +1,341 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.reflect.Field;
+
+/**
+ */
+@SuppressLint("HandlerLeak")
+public class WXCircleViewPager extends ViewPager implements WXGestureObservable {
+
+  private final int SCROLL_TO_NEXT = 1;
+  private WXGesture wxGesture;
+  private boolean isAutoScroll;
+  private long intervalTime = 3 * 1000;
+  private WXSmoothScroller mScroller;
+  private boolean needLoop = true;
+  private boolean scrollable = true;
+  private int mState = ViewPager.SCROLL_STATE_IDLE;
+  private Handler mAutoScrollHandler = new Handler(Looper.getMainLooper()) {
+    @Override
+    public void handleMessage(Message msg) {
+      if (msg.what == SCROLL_TO_NEXT) {
+        WXLogUtils.d("[CircleViewPager] trigger auto play action");
+        showNextItem();
+        this.sendEmptyMessageDelayed(SCROLL_TO_NEXT, intervalTime);
+        return;
+      }
+      super.handleMessage(msg);
+    }
+  };
+
+  @SuppressLint("NewApi")
+  public WXCircleViewPager(Context context) {
+    super(context);
+    init();
+  }
+
+  private void init() {
+    setOverScrollMode(View.OVER_SCROLL_NEVER);
+
+    addOnPageChangeListener(new OnPageChangeListener() {
+      @Override
+      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+      }
+
+      @Override
+      public void onPageSelected(int position) {
+
+      }
+
+      @Override
+      public void onPageScrollStateChanged(int state) {
+        mState = state;
+        WXCirclePageAdapter adapter = getCirclePageAdapter();
+        int currentItemInternal = WXCircleViewPager.super.getCurrentItem();
+        if (needLoop && state == ViewPager.SCROLL_STATE_IDLE && adapter.getCount() > 1) {
+          if (currentItemInternal == adapter.getCount() - 1) {
+            superSetCurrentItem(1, false);
+          } else if (currentItemInternal == 0) {
+            superSetCurrentItem(adapter.getCount() - 2, false);
+          }
+        }
+      }
+    });
+
+    postInitViewPager();
+  }
+
+  /**
+   * Override the Scroller instance with our own class so we can change the
+   * duration
+   */
+  private void postInitViewPager() {
+    if (isInEditMode()) {
+      return;
+    }
+    try {
+      Field scroller = ViewPager.class.getDeclaredField("mScroller");
+      scroller.setAccessible(true);
+      Field interpolator = ViewPager.class
+              .getDeclaredField("sInterpolator");
+      interpolator.setAccessible(true);
+
+      mScroller = new WXSmoothScroller(getContext(),
+              (Interpolator) interpolator.get(null));
+      scroller.set(this, mScroller);
+    } catch (Exception e) {
+      WXLogUtils.e("[CircleViewPager] postInitViewPager: ", e);
+    }
+  }
+
+  @SuppressLint("NewApi")
+  public WXCircleViewPager(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    init();
+  }
+
+  @Override
+  public int getCurrentItem() {
+    return getRealCurrentItem();
+  }
+
+  public int superGetCurrentItem() {
+    return super.getCurrentItem();
+  }
+
+  @Override
+  public boolean onInterceptTouchEvent(MotionEvent ev) {
+    try {
+      return scrollable && super.onInterceptTouchEvent(ev);
+    } catch (IllegalArgumentException e) {
+      e.printStackTrace();
+    } catch (ArrayIndexOutOfBoundsException e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent ev) {
+    if(!scrollable) {
+      return true;
+    }
+    return super.onTouchEvent(ev);
+  }
+
+  @Override
+  public void scrollTo(int x, int y) {
+    if(scrollable || mState != ViewPager.SCROLL_STATE_DRAGGING) {
+      super.scrollTo(x, y);
+    }
+  }
+
+  /**
+   * Start auto scroll. Must be called after {@link #setAdapter(PagerAdapter)}
+   */
+  public void startAutoScroll() {
+    isAutoScroll = true;
+    mAutoScrollHandler.removeCallbacksAndMessages(null);
+    mAutoScrollHandler.sendEmptyMessageDelayed(SCROLL_TO_NEXT, intervalTime);
+  }
+
+  public void pauseAutoScroll(){
+    mAutoScrollHandler.removeCallbacksAndMessages(null);
+  }
+
+  /**
+   * Stop auto scroll.
+   */
+  public void stopAutoScroll() {
+    isAutoScroll = false;
+    mAutoScrollHandler.removeCallbacksAndMessages(null);
+  }
+
+  public boolean isAutoScroll() {
+    return isAutoScroll;
+  }
+
+  @Override
+  public void setCurrentItem(int item) {
+    setRealCurrentItem(item);
+  }
+
+  /**
+   * @return the circlePageAdapter
+   */
+  public WXCirclePageAdapter getCirclePageAdapter() {
+    return (WXCirclePageAdapter) getAdapter();
+  }
+
+  /**
+   * @param circlePageAdapter the circlePageAdapter to set
+   */
+  public void setCirclePageAdapter(WXCirclePageAdapter circlePageAdapter) {
+    this.setAdapter(circlePageAdapter);
+  }
+
+  /**
+   * Get auto scroll interval. The time unit is micro second.
+   * The default time interval is 3000 micro second
+   * @return the intervalTime
+   */
+  public long getIntervalTime() {
+    return intervalTime;
+  }
+
+  /**
+   * Set auto scroll interval. The time unit is micro second.
+   * The default time interval is 3000 micro second
+   * @param intervalTime the intervalTime to set
+   */
+  public void setIntervalTime(long intervalTime) {
+    this.intervalTime = intervalTime;
+  }
+
+  public void setCircle(boolean circle) {
+    needLoop = circle;
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(MotionEvent ev) {
+    switch (ev.getAction()) {
+      case MotionEvent.ACTION_DOWN:
+      case MotionEvent.ACTION_MOVE:
+        mAutoScrollHandler.removeCallbacksAndMessages(null);
+        break;
+      case MotionEvent.ACTION_UP:
+      case MotionEvent.ACTION_CANCEL:
+        if (isAutoScroll()) {
+          mAutoScrollHandler.sendEmptyMessageDelayed(SCROLL_TO_NEXT, intervalTime);
+        }
+        break;
+    }
+    try{
+      boolean result = super.dispatchTouchEvent(ev);
+      if (wxGesture != null) {
+        result |= wxGesture.onTouch(this, ev);
+      }
+      return result;
+    }catch (Exception e){
+      return  false;
+    }
+  }
+
+  public void destory() {
+    mAutoScrollHandler.removeCallbacksAndMessages(null);
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  public int getRealCurrentItem() {
+    int i = super.getCurrentItem();
+    return ((WXCirclePageAdapter) getAdapter()).getRealPosition(i);
+  }
+
+  private void setRealCurrentItem(int item) {
+    superSetCurrentItem(((WXCirclePageAdapter) getAdapter()).getFirst() + item, false);
+  }
+
+  private void superSetCurrentItem(int item, boolean smooth) {
+    try {
+      super.setCurrentItem(item, smooth);
+    } catch (IllegalStateException e) {
+      WXLogUtils.e(e.toString());
+      if (getAdapter() != null) {
+        getAdapter().notifyDataSetChanged();
+        super.setCurrentItem(item, smooth);
+      }
+    }
+  }
+
+  public int getRealCount() {
+    return ((WXCirclePageAdapter) getAdapter()).getRealCount();
+  }
+
+  @Override
+  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+    try {
+      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    } catch (IllegalStateException e) {
+      WXLogUtils.e(e.toString());
+      if (getAdapter() != null) {
+        getAdapter().notifyDataSetChanged();
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+      }
+    }
+  }
+
+  public boolean isScrollable() {
+    return scrollable;
+  }
+
+  public void setScrollable(boolean scrollable) {
+    this.scrollable = scrollable;
+  }
+
+  private void showNextItem() {
+    if (this.getCirclePageAdapter() != null && this.getCirclePageAdapter().isRTL) {
+      if (!needLoop && superGetCurrentItem() == 0) {
+        return;
+      }
+      if (getRealCount() == 2 && superGetCurrentItem() == 0) {
+        superSetCurrentItem(1, true);
+      } else {
+        superSetCurrentItem(superGetCurrentItem() - 1, true);
+      }
+    } else {
+      if (!needLoop && superGetCurrentItem() == getRealCount() - 1) {
+        return;
+      }
+      if (getRealCount() == 2 && superGetCurrentItem() == 1) {
+        superSetCurrentItem(0, true);
+      } else {
+        superSetCurrentItem(superGetCurrentItem() + 1, true);
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXEditText.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXEditText.java
new file mode 100644
index 0000000..acadf8d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXEditText.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Build;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.ViewParent;
+import android.widget.EditText;
+
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+
+/**
+ * Wrapper class for editText
+ */
+@SuppressLint("AppCompatCustomView")
+public class WXEditText extends EditText implements WXGestureObservable {
+
+  private WXGesture wxGesture;
+  private int mLines = 1;
+  private boolean mAllowDisableMovement = true;
+  private boolean mAllowCopyPaste = true;
+
+  public WXEditText(Context context) {
+    super(context);
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+      setBackground(null);
+    } else {
+      setBackgroundDrawable(null);
+    }
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  @Override
+  public void setLines(int lines) {
+    super.setLines(lines);
+    mLines = lines;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    boolean result = super.onTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+
+    ViewParent parent = getParent();
+    if(parent != null){
+      switch (event.getAction() & MotionEvent.ACTION_MASK){
+        case MotionEvent.ACTION_DOWN:
+          if(mLines < getLineCount()) {
+            //scrollable
+            parent.requestDisallowInterceptTouchEvent(true);
+          }
+          break;
+        case MotionEvent.ACTION_UP:
+        case MotionEvent.ACTION_CANCEL:
+          parent.requestDisallowInterceptTouchEvent(false);
+          break;
+      }
+    }
+    return result;
+  }
+
+  @Override
+  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+    super.onSizeChanged(w, h, oldw, oldh);
+    if (getLayout() != null) {
+      int contentH = getLayout().getHeight();
+      //TODO: known issue,set movement to null will make cursor disappear.
+      if (mAllowDisableMovement && h < contentH) {
+        setMovementMethod(null);
+      } else {
+        setMovementMethod(getDefaultMovementMethod());
+      }
+    }
+  }
+
+  public void setAllowDisableMovement(boolean allow) {
+    mAllowDisableMovement = allow;
+  }
+
+  public void setAllowCopyPaste(boolean allow) {
+    mAllowCopyPaste = allow;
+    if (allow) {
+      setLongClickable(true);
+      setCustomSelectionActionModeCallback(null);
+      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+        setCustomInsertionActionModeCallback(null);
+      }
+    } else {
+      setLongClickable(false);
+      ActionMode.Callback callback = new ActionMode.Callback() {
+        @Override
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+          return false;
+        }
+
+        @Override
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+          return false;
+        }
+
+        @Override
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+          return false;
+        }
+
+        @Override
+        public void onDestroyActionMode(ActionMode mode) {
+
+        }
+      };
+      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+        setCustomInsertionActionModeCallback(callback);
+      }
+      setCustomSelectionActionModeCallback(callback);
+    }
+  }
+
+  @Override
+  public boolean onTextContextMenuItem(int id) {
+    return !mAllowCopyPaste || super.onTextContextMenuItem(id);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXFrameLayout.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXFrameLayout.java
new file mode 100644
index 0000000..199d0a0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXFrameLayout.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.support.annotation.Nullable;
+import android.view.MotionEvent;
+import android.view.View;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXDiv;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.utils.WXExceptionUtils;
+import org.apache.weex.utils.WXLogUtils;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * FrameLayout wrapper
+ *
+ */
+public class WXFrameLayout extends BaseFrameLayout implements WXGestureObservable,IRenderStatus<WXDiv>,IRenderResult<WXDiv>{
+
+  private WeakReference<WXDiv> mWeakReference;
+  private WXGesture wxGesture;
+
+
+  public WXFrameLayout(Context context) {
+    super(context);
+  }
+
+  @Nullable
+  @Override
+  public WXDiv getComponent() {
+    return null != mWeakReference ? mWeakReference.get() : null;
+  }
+
+  @Override
+  public void holdComponent(WXDiv component) {
+    mWeakReference = new WeakReference<WXDiv>(component);
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(MotionEvent event) {
+    boolean result = super.dispatchTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+    return result;
+  }
+  @Override
+  protected void dispatchDraw(Canvas canvas) {
+    try {
+      super.dispatchDrawInterval(canvas);
+    } catch (Throwable e) {
+      if (getComponent() != null) {
+        notifyLayerOverFlow();
+        if (null != getComponent()){
+          WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(getComponent().getInstanceId());
+          if (null != instance && null != instance.getApmForInstance() &&!instance.getApmForInstance().hasReportLayerOverDraw){
+            instance.getApmForInstance().hasReportLayerOverDraw = true;
+            reportLayerOverFlowError();
+          }
+        }
+      }
+      WXLogUtils.e("Layer overflow limit error", WXLogUtils.getStackTrace(e));
+    }
+  }
+  private int reportLayerOverFlowError() {
+    int deep = calLayerDeep(this, 0);
+    if (getComponent() != null) {
+      WXExceptionUtils.commitCriticalExceptionRT(getComponent().getInstanceId(),
+              WXErrorCode.WX_RENDER_ERR_LAYER_OVERFLOW,
+              "draw android view",
+              WXErrorCode.WX_RENDER_ERR_LAYER_OVERFLOW.getErrorMsg() + "Layer overflow limit error: " + deep + " layers!",
+              null);
+    }
+    return deep;
+  }
+  private int calLayerDeep(View view, int deep) {
+    deep++;
+    if (view.getParent() != null && view.getParent() instanceof View) {
+      return calLayerDeep((View) view.getParent(), deep);
+    }
+    return deep;
+  }
+
+  public void notifyLayerOverFlow() {
+    if (getComponent() == null)
+      return;
+
+    WXSDKInstance instance = getComponent().getInstance();
+    if (instance == null)
+      return;
+
+    if (instance.getLayerOverFlowListeners() == null)
+      return;
+
+    for (String ref : instance.getLayerOverFlowListeners()) {
+      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instance.getInstanceId(), ref);
+      Map<String, Object> params = new HashMap<>();
+      params.put(Constants.Weex.REF, ref);
+      params.put(Constants.Weex.INSTANCEID, component.getInstanceId());
+      component.fireEvent(Constants.Event.LAYEROVERFLOW, params);
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXHorizontalScrollView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXHorizontalScrollView.java
new file mode 100644
index 0000000..dd6771e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXHorizontalScrollView.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class WXHorizontalScrollView extends HorizontalScrollView implements IWXScroller, WXGestureObservable {
+
+  private WXGesture wxGesture;
+  private ScrollViewListener mScrollViewListener;
+  private List<ScrollViewListener> mScrollViewListeners;
+  private boolean scrollable = true;
+
+  public WXHorizontalScrollView(Context context) {
+    super(context);
+    init();
+  }
+
+  private void init() {
+    setWillNotDraw(false);
+    setOverScrollMode(View.OVER_SCROLL_NEVER);
+  }
+
+  public WXHorizontalScrollView(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    init();
+  }
+
+  @Override
+  protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+    super.onScrollChanged(l, t, oldl, oldt);
+    if (mScrollViewListener != null) {
+      mScrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
+    }
+    if (mScrollViewListeners != null) {
+      for (ScrollViewListener listener : mScrollViewListeners) {
+        listener.onScrollChanged(this, l, t, oldl, oldt);
+      }
+    }
+  }
+
+  public void setScrollViewListener(ScrollViewListener scrollViewListener) {
+    this.mScrollViewListener = scrollViewListener;
+  }
+
+  @Override
+  public void destroy() {
+
+  }
+
+  public void addScrollViewListener(ScrollViewListener scrollViewListener) {
+    if (mScrollViewListeners == null) {
+      mScrollViewListeners = new CopyOnWriteArrayList<>();
+    }
+    if (!mScrollViewListeners.contains(scrollViewListener)) {
+      mScrollViewListeners.add(scrollViewListener);
+    }
+  }
+
+  public void removeScrollViewListener(ScrollViewListener scrollViewListener) {
+    mScrollViewListeners.remove(scrollViewListener);
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(MotionEvent event) {
+    boolean result = super.dispatchTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+    return result;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent ev) {
+    if(!scrollable) {
+      return true; // when scrollable is set to false, then eat the touch event
+    }
+    return super.onTouchEvent(ev);
+  }
+
+  public interface ScrollViewListener {
+
+    void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy);
+  }
+
+  public boolean isScrollable() {
+    return scrollable;
+  }
+
+  public void setScrollable(boolean scrollable) {
+    this.scrollable = scrollable;
+  }
+
+  public Rect getContentFrame() {
+    return new Rect(0, 0, computeHorizontalScrollRange(), computeVerticalScrollRange());
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXImageView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXImageView.java
new file mode 100644
index 0000000..96b3784
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXImageView.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import org.apache.weex.ui.component.WXImage;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.utils.ImageDrawable;
+import org.apache.weex.utils.WXLogUtils;
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+@SuppressLint("AppCompatCustomView")
+public class WXImageView extends ImageView implements WXGestureObservable,
+        IRenderStatus<WXImage>,
+        IRenderResult<WXImage>, WXImage.Measurable {
+
+  private WeakReference<WXImage> mWeakReference;
+  private WXGesture wxGesture;
+  private float[] borderRadius;
+  private boolean gif;
+  private boolean isBitmapReleased = false;
+  private boolean enableBitmapAutoManage = true;
+
+
+  public WXImageView(Context context) {
+    super(context);
+  }
+
+  @Override
+  public void setImageResource(int resId) {
+    Drawable drawable = getResources().getDrawable(resId);
+    setImageDrawable(drawable);
+  }
+
+  public void setImageDrawable(@Nullable Drawable drawable, boolean isGif) {
+    this.gif = isGif;
+    ViewGroup.LayoutParams layoutParams;
+    if ((layoutParams = getLayoutParams()) != null) {
+      Drawable wrapDrawable = ImageDrawable.createImageDrawable(drawable,
+              getScaleType(), borderRadius,
+              layoutParams.width - getPaddingLeft() - getPaddingRight(),
+              layoutParams.height - getPaddingTop() - getPaddingBottom(),
+              isGif);
+      if (wrapDrawable instanceof ImageDrawable) {
+        ImageDrawable imageDrawable = (ImageDrawable) wrapDrawable;
+        if (!Arrays.equals(imageDrawable.getCornerRadii(), borderRadius)) {
+          imageDrawable.setCornerRadii(borderRadius);
+        }
+      }
+      super.setImageDrawable(wrapDrawable);
+      if (mWeakReference != null) {
+        WXImage component = mWeakReference.get();
+        if (component != null) {
+          component.readyToRender();
+        }
+      }
+    }
+  }
+
+  @Override
+  public void setImageDrawable(@Nullable Drawable drawable) {
+    setImageDrawable(drawable, gif);
+  }
+
+  @Override
+  public void setImageBitmap(@Nullable Bitmap bm) {
+    setImageDrawable(bm == null ? null : new BitmapDrawable(getResources(), bm));
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    boolean result = super.onTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+    return result;
+  }
+
+  public void setBorderRadius(@NonNull float[] borderRadius) {
+    this.borderRadius = borderRadius;
+  }
+
+  @Override
+  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+    super.onLayout(changed, left, top, right, bottom);
+    if (changed) {
+      setImageDrawable(getDrawable(), gif);
+    }
+  }
+
+  @Override
+  public void holdComponent(WXImage component) {
+    mWeakReference = new WeakReference<>(component);
+  }
+
+  @Nullable
+  @Override
+  public WXImage getComponent() {
+    return null != mWeakReference ? mWeakReference.get() : null;
+  }
+
+  @Override
+  public int getNaturalWidth() {
+    Drawable drawable = getDrawable();
+    if (drawable != null) {
+      if (drawable instanceof ImageDrawable) {
+        return ((ImageDrawable) drawable).getBitmapWidth();
+      } else if (drawable instanceof BitmapDrawable) {
+        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+        if (bitmap != null) {
+          return bitmap.getWidth();
+        } else {
+          WXLogUtils.w("WXImageView", "Bitmap on " + drawable.toString() + " is null");
+        }
+      } else {
+        WXLogUtils.w("WXImageView", "Not supported drawable type: " + drawable.getClass().getSimpleName());
+      }
+    }
+    return -1;
+  }
+
+  @Override
+  public int getNaturalHeight() {
+    Drawable drawable = getDrawable();
+    if (drawable != null) {
+      if (drawable instanceof ImageDrawable) {
+        return ((ImageDrawable) drawable).getBitmapHeight();
+      } else if (drawable instanceof BitmapDrawable) {
+        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+        if (bitmap != null) {
+          return bitmap.getHeight();
+        } else {
+          WXLogUtils.w("WXImageView", "Bitmap on " + drawable.toString() + " is null");
+        }
+      } else {
+        WXLogUtils.w("WXImageView", "Not supported drawable type: " + drawable.getClass().getSimpleName());
+      }
+    }
+    return -1;
+  }
+
+  private boolean mOutWindowVisibilityChangedReally;
+  @Override
+  public void dispatchWindowVisibilityChanged(int visibility) {
+    mOutWindowVisibilityChangedReally = true;
+    super.dispatchWindowVisibilityChanged(visibility);
+    mOutWindowVisibilityChangedReally = false;
+  }
+
+  @Override
+  protected void onWindowVisibilityChanged(int visibility) {
+    super.onWindowVisibilityChanged(visibility);
+    if(mOutWindowVisibilityChangedReally){
+      if(visibility == View.VISIBLE){
+        autoRecoverImage();
+      }else{
+        autoReleaseImage();
+      }
+    }
+  }
+
+
+  @Override
+  protected void onAttachedToWindow() {
+    super.onAttachedToWindow();
+    autoRecoverImage();
+  }
+
+  @Override
+  protected void onDetachedFromWindow() {
+    super.onDetachedFromWindow();
+    autoReleaseImage();
+
+  }
+
+
+  @Override
+  public void onStartTemporaryDetach () {
+    super.onStartTemporaryDetach();
+    autoReleaseImage();
+
+  }
+
+
+  @Override
+  public void onFinishTemporaryDetach () {
+    super.onFinishTemporaryDetach();
+    autoRecoverImage();
+  }
+
+
+  public void setEnableBitmapAutoManage(boolean enableBitmapAutoManage) {
+    this.enableBitmapAutoManage = enableBitmapAutoManage;
+  }
+
+  public void autoReleaseImage(){
+    if(enableBitmapAutoManage) {
+      if (!isBitmapReleased) {
+        isBitmapReleased = true;
+        WXImage image = getComponent();
+        if (image != null) {
+          image.autoReleaseImage();
+        }
+      }
+    }
+  }
+
+  public void autoRecoverImage(){
+    if(enableBitmapAutoManage){
+      if(isBitmapReleased){
+        WXImage image = getComponent();
+        if(image != null){
+          image.autoRecoverImage();
+        }
+        isBitmapReleased = false;
+      }
+    }
+  }
+
+
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXLoadingLayout.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXLoadingLayout.java
new file mode 100644
index 0000000..d728efd
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXLoadingLayout.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.content.Context;
+
+/**
+ * Created by lixinke on 16/9/19.
+ */
+public class WXLoadingLayout extends WXBaseRefreshLayout {
+
+  public WXLoadingLayout(Context context) {
+    super(context);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXRefreshLayout.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXRefreshLayout.java
new file mode 100644
index 0000000..78bcf75
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXRefreshLayout.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.content.Context;
+
+/**
+ * Created by lixinke on 16/9/19.
+ */
+public class WXRefreshLayout extends WXBaseRefreshLayout {
+
+  public WXRefreshLayout(Context context) {
+    super(context);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXScrollView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXScrollView.java
new file mode 100644
index 0000000..8932c02
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXScrollView.java
@@ -0,0 +1,467 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Handler.Callback;
+import android.os.Message;
+import android.support.v4.view.NestedScrollingChild;
+import android.support.v4.view.NestedScrollingChildHelper;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ScrollView;
+
+import org.apache.weex.common.WXThread;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXScroller;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXReflectionUtils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * Custom-defined scrollView
+ */
+public class WXScrollView extends ScrollView implements Callback, IWXScroller,
+        WXGestureObservable,NestedScrollingChild {
+
+  private NestedScrollingChildHelper childHelper;
+  private float ox;
+  private float oy;
+  private int[] consumed = new int[2];
+  private int[] offsetInWindow = new int[2];
+
+  int mScrollX;
+  int mScrollY;
+  private WXGesture wxGesture;
+  private List<WXScrollViewListener> mScrollViewListeners;
+  private WXScroller mWAScroller;
+  //sticky
+  private View mCurrentStickyView;
+  private boolean mRedirectTouchToStickyView;
+  private int mStickyOffset;
+  private boolean mHasNotDoneActionDown = true;
+  @SuppressLint("HandlerLeak")
+  private Handler mScrollerTask;
+  private int mInitialPosition;
+  private int mCheckTime = 100;
+  /**
+   * The location of mCurrentStickyView
+   */
+  private int[] mStickyP = new int[2];
+  /**
+   * Location of the scrollView
+   */
+  private Rect mScrollRect;
+  private int[] stickyScrollerP = new int[2];
+  private int[] stickyViewP = new int[2];
+  private boolean scrollable = true;
+
+  public WXScrollView(Context context) {
+    super(context);
+    mScrollViewListeners = new ArrayList<>();
+    init();
+    try {
+      WXReflectionUtils.setValue(this, "mMinimumVelocity", 5);
+    } catch (Exception e) {
+      WXLogUtils.e("[WXScrollView] WXScrollView: ", e);
+    }
+  }
+
+  private void init() {
+    setWillNotDraw(false);
+    startScrollerTask();
+    setOverScrollMode(View.OVER_SCROLL_NEVER);
+    childHelper = new NestedScrollingChildHelper(this);
+    childHelper.setNestedScrollingEnabled(true);
+  }
+
+  public void startScrollerTask() {
+    if (mScrollerTask == null) {
+      mScrollerTask = new Handler(WXThread.secure(this));
+    }
+    mInitialPosition = getScrollY();
+    mScrollerTask.sendEmptyMessageDelayed(0, mCheckTime);
+  }
+
+  public WXScrollView(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    init();
+  }
+
+  public WXScrollView(Context context, AttributeSet attrs, int defStyle) {
+    super(context, attrs, defStyle);
+    setOverScrollMode(View.OVER_SCROLL_NEVER);
+  }
+
+  /**
+   * Add listener for scrollView.
+   */
+  public void addScrollViewListener(WXScrollViewListener scrollViewListener) {
+    if (!mScrollViewListeners.contains(scrollViewListener)) {
+      mScrollViewListeners.add(scrollViewListener);
+    }
+  }
+
+  public void removeScrollViewListener(WXScrollViewListener scrollViewListener) {
+    mScrollViewListeners.remove(scrollViewListener);
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(MotionEvent ev) {
+    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+      mRedirectTouchToStickyView = true;
+    }
+
+    if (mRedirectTouchToStickyView) {
+      mRedirectTouchToStickyView = mCurrentStickyView != null;
+
+      if (mRedirectTouchToStickyView) {
+        mRedirectTouchToStickyView = ev.getY() <= mCurrentStickyView.getHeight()
+                && ev.getX() >= mCurrentStickyView.getLeft()
+                && ev.getX() <= mCurrentStickyView.getRight();
+      }
+    }
+
+    if (mRedirectTouchToStickyView) {
+      if (mScrollRect == null) {
+        mScrollRect = new Rect();
+        getGlobalVisibleRect(mScrollRect);
+      }
+      mCurrentStickyView.getLocationOnScreen(stickyViewP);
+      ev.offsetLocation(0, stickyViewP[1] - mScrollRect.top);
+    }
+    boolean result = super.dispatchTouchEvent(ev);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, ev);
+    }
+    return result;
+  }
+
+  @Override
+  protected void dispatchDraw(Canvas canvas) {
+    super.dispatchDraw(canvas);
+    if (mCurrentStickyView != null) {
+      canvas.save();
+      mCurrentStickyView.getLocationOnScreen(mStickyP);
+      int realOffset = (mStickyOffset <= 0 ? mStickyOffset : 0);
+      canvas.translate(mStickyP[0], getScrollY() + realOffset);
+      canvas.clipRect(0, realOffset, mCurrentStickyView.getWidth(),
+              mCurrentStickyView.getHeight());
+      mCurrentStickyView.draw(canvas);
+      canvas.restore();
+    }
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent ev) {
+    if(!scrollable) {
+      return true; // when scrollable is set to false, then eat the touch event
+    }
+    if (mRedirectTouchToStickyView) {
+
+      if (mScrollRect == null) {
+        mScrollRect = new Rect();
+        getGlobalVisibleRect(mScrollRect);
+      }
+      mCurrentStickyView.getLocationOnScreen(stickyViewP);
+      ev.offsetLocation(0, -(stickyViewP[1] - mScrollRect.top));
+    }
+
+    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+      mHasNotDoneActionDown = false;
+    }
+
+    if (mHasNotDoneActionDown) {
+      MotionEvent down = MotionEvent.obtain(ev);
+      down.setAction(MotionEvent.ACTION_DOWN);
+      mHasNotDoneActionDown = false;
+      down.recycle();
+    }
+
+    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+      ox = ev.getX();
+      oy = ev.getY();
+      // Dispatch touch event to parent view
+      startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL | ViewCompat.SCROLL_AXIS_VERTICAL);
+    }
+
+    if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) {
+      mHasNotDoneActionDown = true;
+      // stop nested scrolling dispatch
+      stopNestedScroll();
+    }
+
+    if (ev.getAction() == MotionEvent.ACTION_MOVE) {
+      float clampedX = ev.getX();
+      float clampedY = ev.getY();
+      int dx = (int) (ox - clampedX);
+      int dy = (int) (oy - clampedY);
+
+      if (dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)) {
+        // sub dx/dy was consumed by parent view!!!
+        ev.setLocation(clampedX+consumed[0],clampedY+consumed[1]);
+      }
+      ox = ev.getX();
+      oy = ev.getY();
+    }
+
+    return super.onTouchEvent(ev);
+  }
+
+  @Override
+  public void setNestedScrollingEnabled(boolean enabled) {
+    childHelper.setNestedScrollingEnabled(enabled);
+  }
+
+  @Override
+  public boolean isNestedScrollingEnabled() {
+    return childHelper.isNestedScrollingEnabled();
+  }
+
+  @Override
+  public boolean startNestedScroll(int axes) {
+    return childHelper.startNestedScroll(axes);
+  }
+
+  @Override
+  public void stopNestedScroll() {
+    childHelper.stopNestedScroll();
+  }
+
+  @Override
+  public boolean hasNestedScrollingParent() {
+    return childHelper.hasNestedScrollingParent();
+  }
+
+  public boolean isScrollable() {
+    return scrollable;
+  }
+
+  public void setScrollable(boolean scrollable) {
+    this.scrollable = scrollable;
+  }
+
+  @Override
+  public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
+    return childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
+  }
+
+  @Override
+  public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+    return childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
+  }
+
+  @Override
+  public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
+    return childHelper.dispatchNestedFling(velocityX, velocityY, consumed);
+  }
+
+  @Override
+  public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
+    return childHelper.dispatchNestedPreFling(velocityX, velocityY);
+  }
+
+  @Override
+  public boolean onNestedPreFling(View target, float velocityX,
+                                  float velocityY) {
+    return dispatchNestedPreFling(velocityX, velocityY);
+  }
+
+  @Override
+  public boolean onNestedFling(View target, float velocityX, float velocityY,
+                               boolean consumed) {
+    return dispatchNestedFling(velocityX, velocityY, consumed);
+  }
+
+  @Override
+  public void fling(int velocityY) {
+    super.fling(velocityY);
+    if (mScrollerTask != null) {
+      mScrollerTask.removeMessages(0);
+    }
+    startScrollerTask();
+  }
+
+  @Override
+  protected void onScrollChanged(int x, int y, int oldx, int oldy) {
+    mScrollX = getScrollX();
+    mScrollY = getScrollY();
+    onScroll(WXScrollView.this, mScrollX, mScrollY);
+    View view = getChildAt(getChildCount() - 1);
+    if (view == null) {
+      return;
+    }
+    int d = view.getBottom();
+    d -= (getHeight() + mScrollY);
+    if (d == 0) {
+      onScrollToBottom(mScrollX, mScrollY);
+    }
+    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
+    for (int i = 0; i < count; ++i) {
+      mScrollViewListeners.get(i).onScrollChanged(this, x, y, oldx, oldy);
+    }
+
+    showStickyView();
+  }
+
+  protected void onScroll(WXScrollView scrollView, int x, int y) {
+    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
+    for (int i = 0; i < count; ++i) {
+      mScrollViewListeners.get(i).onScroll(this, x, y);
+    }
+  }
+
+  protected void onScrollToBottom(int x, int y) {
+    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
+    for (int i = 0; i < count; ++i) {
+      mScrollViewListeners.get(i).onScrollToBottom(this, x, y);
+    }
+  }
+
+  private void showStickyView() {
+    if(mWAScroller == null){
+      return;
+    }
+    View curStickyView = procSticky(mWAScroller.getStickMap());
+
+    if (curStickyView != null) {
+      mCurrentStickyView = curStickyView;
+    } else {
+      mCurrentStickyView = null;
+    }
+  }
+
+  private View procSticky(Map<String, Map<String, WXComponent>> mStickyMap) {
+    if (mStickyMap == null) {
+      return null;
+    }
+    Map<String, WXComponent> stickyMap = mStickyMap.get(mWAScroller.getRef());
+    if (stickyMap == null) {
+      return null;
+    }
+
+    Iterator<Entry<String, WXComponent>> iterator = stickyMap.entrySet().iterator();
+    Entry<String, WXComponent> entry = null;
+    WXComponent stickyData;
+    while (iterator.hasNext()) {
+      entry = iterator.next();
+      stickyData = entry.getValue();
+
+      getLocationOnScreen(stickyScrollerP);
+      stickyData.getHostView().getLocationOnScreen(stickyViewP);
+      int parentH = 0;
+      if(stickyData.getParent()!=null && stickyData.getParent().getRealView()!=null){
+        parentH=stickyData.getParent().getRealView().getHeight();
+      }
+      int stickyViewH = stickyData.getHostView().getHeight();
+      int stickyShowPos = stickyScrollerP[1];
+      int stickyStartHidePos = -parentH + stickyScrollerP[1] + stickyViewH;
+      if (stickyViewP[1] <= stickyShowPos && stickyViewP[1] >= (stickyStartHidePos - stickyViewH)) {
+        mStickyOffset = stickyViewP[1] - stickyStartHidePos;
+        stickyData.setStickyOffset(stickyViewP[1]-stickyScrollerP[1]);
+        return stickyData.getHostView();
+      }else{
+        stickyData.setStickyOffset(0);
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public boolean handleMessage(Message msg) {
+    switch (msg.what) {
+      case 0:
+        if (mScrollerTask != null) {
+          mScrollerTask.removeMessages(0);
+        }
+        int newPosition = getScrollY();
+        if (mInitialPosition - newPosition == 0) {//has stopped
+          onScrollStopped(WXScrollView.this, getScrollX(), getScrollY());
+        } else {
+          onScroll(WXScrollView.this, getScrollX(), getScrollY());
+          mInitialPosition = getScrollY();
+          if (mScrollerTask != null) {
+            mScrollerTask.sendEmptyMessageDelayed(0, mCheckTime);
+          }
+        }
+        break;
+      default:
+        break;
+    }
+    return true;
+  }
+
+  protected void onScrollStopped(WXScrollView scrollView, int x, int y) {
+    int count = mScrollViewListeners == null ? 0 : mScrollViewListeners.size();
+    for (int i = 0; i < count; ++i) {
+      mScrollViewListeners.get(i).onScrollStopped(this, x, y);
+    }
+  }
+
+  @Override
+  public void destroy() {
+    if (mScrollerTask != null) {
+      mScrollerTask.removeCallbacksAndMessages(null);
+    }
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  public Rect getContentFrame() {
+    return new Rect(0, 0, computeHorizontalScrollRange(), computeVerticalScrollRange());
+  }
+
+  public interface WXScrollViewListener {
+
+    void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy);
+
+    void onScrollToBottom(WXScrollView scrollView, int x, int y);
+
+    void onScrollStopped(WXScrollView scrollView, int x, int y);
+
+    void onScroll(WXScrollView scrollView, int x, int y);
+  }
+
+  public void setWAScroller(WXScroller mWAScroller) {
+    this.mWAScroller = mWAScroller;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXSmoothScroller.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXSmoothScroller.java
new file mode 100644
index 0000000..e943ce8
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXSmoothScroller.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.view.animation.Interpolator;
+import android.widget.Scroller;
+
+/**
+ * modify the scrollFactor
+ */
+public class WXSmoothScroller extends Scroller {
+
+  private double mScrollFactor = 1;
+
+  public WXSmoothScroller(Context context) {
+    super(context);
+  }
+
+  public WXSmoothScroller(Context context, Interpolator interpolator) {
+    super(context, interpolator);
+  }
+
+  @SuppressLint("NewApi")
+  public WXSmoothScroller(Context context, Interpolator interpolator, boolean flywheel) {
+    super(context, interpolator, flywheel);
+  }
+
+  /**
+   * Set the factor by which the duration will change
+   */
+  public void setScrollDurationFactor(double scrollFactor) {
+    mScrollFactor = scrollFactor;
+  }
+
+  @Override
+  public void startScroll(int startX, int startY, int dx, int dy, int duration) {
+    super.startScroll(startX, startY, dx, dy, (int) (duration * mScrollFactor));
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXSwitchView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXSwitchView.java
new file mode 100644
index 0000000..f02fe63
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXSwitchView.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.v7.widget.SwitchCompat;
+import android.view.Gravity;
+import android.view.MotionEvent;
+
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+
+public class WXSwitchView extends SwitchCompat implements WXGestureObservable {
+
+  private WXGesture wxGesture;
+
+  public WXSwitchView(Context context) {
+    super(context);
+    setShowText(false);
+    setGravity(Gravity.CENTER_VERTICAL);
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    boolean result = super.onTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+    return result;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXTextView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXTextView.java
new file mode 100644
index 0000000..06073b3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXTextView.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.support.annotation.ColorInt;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.PopupMenu;
+import android.text.Layout;
+import android.text.TextUtils;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import org.apache.weex.ui.component.WXText;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import java.lang.ref.WeakReference;
+
+/**
+ * TextView wrapper
+ */
+public class WXTextView extends View implements WXGestureObservable, IWXTextView,
+        IRenderStatus<WXText>, IRenderResult<WXText> {
+
+  private WeakReference<WXText> mWeakReference;
+  private WXGesture wxGesture;
+  private Layout textLayout;
+  private boolean mIsLabelSet = false;
+
+  public WXTextView(Context context) {
+    super(context);
+  }
+
+  @Override
+  protected void onDraw(Canvas canvas) {
+    super.onDraw(canvas);
+    canvas.save();
+    Layout layout= getTextLayout();
+    if(layout!=null){
+      canvas.translate(getPaddingLeft(),getPaddingTop());
+      layout.draw(canvas);
+    }
+    canvas.restore();
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    boolean result = super.onTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+    return result;
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  @Override
+  public CharSequence getText() {
+    return textLayout != null ? textLayout.getText() : null;
+  }
+
+  public Layout getTextLayout() {
+    return textLayout;
+  }
+
+  public void setTextLayout(Layout layout) {
+    this.textLayout = layout;
+    if(layout!=null && !mIsLabelSet){
+      setContentDescription(layout.getText());
+    }
+    if (mWeakReference != null) {
+      WXText wxText = mWeakReference.get();
+      if (wxText != null) {
+        wxText.readyToRender();
+      }
+    }
+  }
+
+  public void setAriaLabel(String label){
+    if(!TextUtils.isEmpty(label)){
+      mIsLabelSet = true;
+      setContentDescription(label);
+    }else{
+      mIsLabelSet = false;
+      if(textLayout != null){
+        setContentDescription(textLayout.getText());
+      }
+    }
+
+  }
+
+  /**
+   * Sets the text color for the text layout, it will be invalid
+   * when {@link #setTextLayout(Layout)} happens, and color has to be
+   * reset.
+   *
+   * @see #setTextLayout(Layout)
+   *
+   * @param color A color value in the form 0xAARRGGBB.
+   */
+  public void setTextColor(@ColorInt int color) {
+    Layout layout = getTextLayout();
+    if (layout != null) {
+      layout.getPaint().setColor(color);
+    }
+  }
+
+  @Override
+  public void holdComponent(WXText component) {
+    mWeakReference = new WeakReference<>(component);
+  }
+
+  @Nullable
+  @Override
+  public WXText getComponent() {
+    return null != mWeakReference ? mWeakReference.get() : null;
+  }
+
+  public void enableCopy(boolean enable) {
+    if (enable) {
+      setOnLongClickListener(new OnLongClickListener() {
+        @Override
+        public boolean onLongClick(View v) {
+          PopupMenu popupMenu = new PopupMenu(getContext(), WXTextView.this);
+          String s = "Copy";
+          try {
+            s = getContext().getResources().getString(android.R.string.copy);
+          } catch (Throwable t) {
+            //ignore
+          }
+          final String title = s;
+          popupMenu.getMenu().add(title);
+          popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+            @Override
+            public boolean onMenuItemClick(MenuItem item) {
+              if (title.equals(item.getTitle())) {
+                String data = getText().toString();
+                ClipboardManager clipboardManager = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+                if (clipboardManager != null) {
+                  ClipData clipData = ClipData.newPlainText(data, data);
+                  clipboardManager.setPrimaryClip(clipData);
+                }
+                return true;
+              }
+              return false;
+            }
+          });
+          popupMenu.show();
+          return true;
+        }
+      });
+    } else {
+      setOnLongClickListener(null);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXVideoView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXVideoView.java
new file mode 100644
index 0000000..4df2d4a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXVideoView.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Rect;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.MediaController;
+import android.widget.ProgressBar;
+import android.widget.VideoView;
+
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.utils.WXResourceUtils;
+
+
+public class WXVideoView extends VideoView implements WXGestureObservable {
+
+  private WXGesture wxGesture;
+  private VideoPlayListener mVideoPauseListener;
+
+  public WXVideoView(Context context) {
+    super(context);
+  }
+
+  @Override
+  public void registerGestureListener(WXGesture wxGesture) {
+    this.wxGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return wxGesture;
+  }
+
+  public void setOnVideoPauseListener(VideoPlayListener listener) {
+    mVideoPauseListener = listener;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    boolean result = super.onTouchEvent(event);
+    if (wxGesture != null) {
+      result |= wxGesture.onTouch(this, event);
+    }
+    return result;
+  }
+
+  @Override
+  public void start() {
+    super.start();
+    if (mVideoPauseListener != null) {
+      mVideoPauseListener.onStart();
+    }
+  }
+
+  @Override
+  public void pause() {
+    super.pause();
+    if (mVideoPauseListener != null) {
+      mVideoPauseListener.onPause();
+    }
+  }
+
+  public interface VideoPlayListener {
+
+    void onPause();
+
+    void onStart();
+  }
+
+
+  public static class Wrapper extends FrameLayout implements ViewTreeObserver.OnGlobalLayoutListener {
+
+    private WXVideoView mVideoView;
+    private ProgressBar mProgressBar;
+    private MediaController mMediaController;
+    private Uri mUri;
+    private MediaPlayer.OnPreparedListener mOnPreparedListener;
+    private MediaPlayer.OnErrorListener mOnErrorListener;
+    private MediaPlayer.OnCompletionListener mOnCompletionListener;
+    private WXVideoView.VideoPlayListener mVideoPlayListener;
+    private boolean mControls = true;
+
+    public Wrapper(Context context) {
+      super(context);
+      init(context);
+    }
+
+    public Wrapper(Context context, AttributeSet attrs) {
+      super(context, attrs);
+      init(context);
+    }
+
+    public Wrapper(Context context, AttributeSet attrs, int defStyleAttr) {
+      super(context, attrs, defStyleAttr);
+      init(context);
+    }
+
+    private void init(Context context) {
+      setBackgroundColor(WXResourceUtils.getColor("#ee000000"));
+      mProgressBar = new ProgressBar(context);
+      FrameLayout.LayoutParams pLayoutParams =
+              new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
+                      FrameLayout.LayoutParams.WRAP_CONTENT);
+      mProgressBar.setLayoutParams(pLayoutParams);
+      pLayoutParams.gravity = Gravity.CENTER;
+      addView(mProgressBar);
+
+      getViewTreeObserver().addOnGlobalLayoutListener(this);
+    }
+
+    public ProgressBar getProgressBar() {
+      return mProgressBar;
+    }
+
+    public
+    @Nullable
+    WXVideoView getVideoView() {
+      return mVideoView;
+    }
+
+    /**
+     * Create if not existed. Will cause request focus.
+     *
+     * @return
+     */
+    public
+    @NonNull
+    WXVideoView createIfNotExist() {
+      if (mVideoView == null) {
+        createVideoView();
+      }
+      return mVideoView;
+    }
+
+    public
+    @Nullable
+    MediaController getMediaController() {
+      return mMediaController;
+    }
+
+    public void setVideoURI(Uri uri) {
+      mUri = uri;
+      if (mVideoView != null) {
+        mVideoView.setVideoURI(uri);
+      }
+    }
+
+    public void start() {
+      if (mVideoView != null) {
+        mVideoView.start();
+      }
+    }
+
+    public void pause() {
+      if (mVideoView != null) {
+        mVideoView.pause();
+      }
+    }
+
+    public void stopPlayback() {
+      if (mVideoView != null) {
+        mVideoView.stopPlayback();
+      }
+    }
+
+    public void resume() {
+      if (mVideoView != null) {
+        mVideoView.resume();
+      }
+    }
+
+    public void setOnErrorListener(MediaPlayer.OnErrorListener l) {
+      mOnErrorListener = l;
+      if (mVideoView != null) {
+        mVideoView.setOnErrorListener(l);
+      }
+    }
+
+    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
+      mOnPreparedListener = l;
+      if (mVideoView != null) {
+        mVideoView.setOnPreparedListener(l);
+      }
+
+    }
+
+    public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) {
+      mOnCompletionListener = l;
+      if (mVideoView != null) {
+        mVideoView.setOnCompletionListener(l);
+      }
+    }
+
+    public void setOnVideoPauseListener(VideoPlayListener listener) {
+      mVideoPlayListener = listener;
+      if (mVideoView != null) {
+        mVideoView.setOnVideoPauseListener(listener);
+      }
+    }
+
+    public void setControls(boolean controls) {
+      mControls = controls;
+      if (mVideoView != null && mMediaController != null) {
+        if (!mControls) {
+          mMediaController.setVisibility(View.GONE);
+        } else {
+          mMediaController.setVisibility(View.VISIBLE);
+        }
+      }
+    }
+
+    private synchronized void createVideoView() {
+      if(mVideoView != null){
+        return;
+      }
+      Context context = getContext();
+      WXVideoView video = new WXVideoView(context);
+      FrameLayout.LayoutParams videoLayoutParams =
+              new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+                      FrameLayout.LayoutParams.MATCH_PARENT);
+      videoLayoutParams.gravity = Gravity.CENTER;
+      video.setLayoutParams(videoLayoutParams);
+      addView(video, 0);//first child
+      video.setOnErrorListener(mOnErrorListener);
+      video.setOnPreparedListener(mOnPreparedListener);
+      video.setOnCompletionListener(mOnCompletionListener);
+      video.setOnVideoPauseListener(mVideoPlayListener);
+      MediaController controller = new MediaController(context);
+      controller.setAnchorView(this);
+      video.setMediaController(controller);
+      controller.setMediaPlayer(video);
+      if (!mControls) {
+        controller.setVisibility(View.GONE);
+      } else {
+        controller.setVisibility(View.VISIBLE);
+      }
+      mMediaController = controller;
+      mVideoView = video;
+      mVideoView.setZOrderOnTop(true);
+
+      if(mUri != null) {
+        setVideoURI(mUri);
+      }
+    }
+
+    @SuppressLint("NewApi")
+    private void removeSelfFromViewTreeObserver() {
+      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+        getViewTreeObserver().removeOnGlobalLayoutListener(this);
+      } else {
+        getViewTreeObserver().removeGlobalOnLayoutListener(this);
+      }
+    }
+
+
+    public boolean createVideoViewIfVisible(){
+      Rect visibleRect = new Rect();
+      if (mVideoView != null) {
+        return true;
+      } else if (getGlobalVisibleRect(visibleRect) && !visibleRect.isEmpty()) {
+        createVideoView();
+        return true;
+      }
+      return false;
+    }
+
+    @Override
+    public void onGlobalLayout() {
+      if(createVideoViewIfVisible()){
+        removeSelfFromViewTreeObserver();
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/WXWebView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/WXWebView.java
new file mode 100644
index 0000000..bca5350
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/WXWebView.java
@@ -0,0 +1,376 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.webkit.JavascriptInterface;
+import android.webkit.JsPromptResult;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.FrameLayout;
+import android.widget.ProgressBar;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+
+public class WXWebView implements IWebView {
+
+    private Context mContext;
+    private String mOrigin;
+    private WebView mWebView;
+    private ProgressBar mProgressBar;
+    private boolean mShowLoading = true;
+    private Handler mMessageHandler;
+    private static final int POST_MESSAGE = 1;
+    private static final String BRIDGE_NAME = "__WEEX_WEB_VIEW_BRIDGE";
+    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
+    // downgraded by CVE-2012-6636(https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6636)
+    private static final boolean DOWNGRADE_JS_INTERFACE = SDK_VERSION < 17;
+
+    private OnErrorListener mOnErrorListener;
+    private OnPageListener mOnPageListener;
+    private OnMessageListener mOnMessageListener;
+
+    public WXWebView(Context context, String origin) {
+        mContext = context;
+        mOrigin = origin;
+    }
+
+    @Override
+    public View getView() {
+        FrameLayout root = new FrameLayout(mContext);
+        root.setBackgroundColor(Color.WHITE);
+
+        mWebView = new WebView(mContext);//mContext.getApplicationContext();
+        FrameLayout.LayoutParams wvLayoutParams =
+                new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT);
+        wvLayoutParams.gravity = Gravity.CENTER;
+        mWebView.setLayoutParams(wvLayoutParams);
+        root.addView(mWebView);
+        initWebView(mWebView);
+
+        mProgressBar = new ProgressBar(mContext);
+        showProgressBar(false);
+        FrameLayout.LayoutParams pLayoutParams =
+                new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
+                        FrameLayout.LayoutParams.WRAP_CONTENT);
+        mProgressBar.setLayoutParams(pLayoutParams);
+        pLayoutParams.gravity = Gravity.CENTER;
+        root.addView(mProgressBar);
+
+        mMessageHandler = new MessageHandler(this);
+
+        return root;
+    }
+
+    @Override
+    public void destroy() {
+        if (getWebView() != null) {
+            getWebView().removeAllViews();
+            getWebView().destroy();
+            mWebView = null;
+        }
+    }
+
+    @Override
+    public void loadUrl(String url) {
+        if(getWebView() == null)
+            return;
+        getWebView().loadUrl(url);
+    }
+
+    @Override
+    public void loadDataWithBaseURL(String source) {
+        if(getWebView() == null)
+            return;
+        getWebView().loadDataWithBaseURL(mOrigin, source, "text/html", "utf-8", null);
+    }
+
+    @Override
+    public void reload() {
+        if(getWebView() == null)
+            return;
+        getWebView().reload();
+    }
+
+    @Override
+    public void goBack() {
+        if(getWebView() == null)
+            return;
+        getWebView().goBack();
+    }
+
+    @Override
+    public void goForward() {
+        if(getWebView() == null)
+            return;
+        getWebView().goForward();
+    }
+
+    @Override
+    public void postMessage(Object msg) {
+        if (getWebView() == null) return;
+
+        try {
+            JSONObject initData = new JSONObject();
+            initData.put("type", "message");
+            initData.put("data", msg);
+            initData.put("origin", mOrigin);
+            evaluateJS("javascript:(function () {"
+                + "var initData = " + initData.toString() + ";"
+                + "try {"
+                + "var event = new MessageEvent('message', initData);"
+                + "window.dispatchEvent(event);"
+                + "} catch (e) {}"
+                + "})();");
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /*@Override
+    public void setVisibility(int visibility) {
+        if (mRootView != null) {
+            mRootView.setVisibility(visibility);
+        }
+    }*/
+
+    @Override
+    public void setShowLoading(boolean shown) {
+        mShowLoading = shown;
+    }
+
+    @Override
+    public void setOnErrorListener(OnErrorListener listener) {
+        mOnErrorListener = listener;
+    }
+
+    @Override
+    public void setOnPageListener(OnPageListener listener) {
+        mOnPageListener = listener;
+    }
+
+    @Override
+    public void setOnMessageListener(OnMessageListener listener) {
+        mOnMessageListener = listener;
+    }
+
+    private void showProgressBar(boolean shown) {
+        if (mShowLoading) {
+            mProgressBar.setVisibility(shown ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    private void showWebView(boolean shown) {
+        mWebView.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    private @Nullable WebView getWebView() {
+        //TODO: remove this, duplicate with getView semantically.
+        return mWebView;
+    }
+
+    @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"})
+    private void initWebView(WebView wv) {
+        WebSettings settings = wv.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setAppCacheEnabled(true);
+        settings.setUseWideViewPort(true);
+        settings.setDomStorageEnabled(true);
+        settings.setSupportZoom(false);
+        settings.setBuiltInZoomControls(false);
+        settings.setAllowFileAccess(false);
+        wv.setWebViewClient(new WebViewClient() {
+
+            @Override
+            public boolean shouldOverrideUrlLoading(WebView view, String url) {
+                view.loadUrl(url);
+                WXLogUtils.v("tag", "onPageOverride " + url);
+                return true;
+            }
+
+            @Override
+            public void onPageStarted(WebView view, String url, Bitmap favicon) {
+                super.onPageStarted(view, url, favicon);
+                WXLogUtils.v("tag", "onPageStarted " + url);
+                if (mOnPageListener != null) {
+                    mOnPageListener.onPageStart(url);
+                }
+            }
+
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                super.onPageFinished(view, url);
+                WXLogUtils.v("tag", "onPageFinished " + url);
+                if (mOnPageListener != null) {
+                    mOnPageListener.onPageFinish(url, view.canGoBack(), view.canGoForward());
+                }
+                if (mOnMessageListener != null) {
+                    evaluateJS("javascript:(window.postMessage = function(message, targetOrigin) {"
+                        + "if (message == null || !targetOrigin) return;"
+                        + (DOWNGRADE_JS_INTERFACE
+                        ? "prompt('" + BRIDGE_NAME + "://postMessage?message=' + JSON.stringify(message) + '&targetOrigin=' + targetOrigin)"
+                        : BRIDGE_NAME + ".postMessage(JSON.stringify(message), targetOrigin);")
+                        + "})");
+                }
+            }
+
+            @Override
+            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+                super.onReceivedError(view, request, error);
+                if (mOnErrorListener != null) {
+                    //mOnErrorListener.onError("error", "page error code:" + error.getErrorCode() + ", desc:" + error.getDescription() + ", url:" + request.getUrl());
+                    mOnErrorListener.onError("error", "page error");
+                }
+            }
+
+            @Override
+            public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
+                super.onReceivedHttpError(view, request, errorResponse);
+                if (mOnErrorListener != null) {
+                    mOnErrorListener.onError("error", "http error");
+                }
+            }
+
+            @Override
+            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+                super.onReceivedSslError(view, handler, error);
+                if (mOnErrorListener != null) {
+                    mOnErrorListener.onError("error", "ssl error");
+                }
+            }
+        });
+        wv.setWebChromeClient(new WebChromeClient() {
+            @Override
+            public void onProgressChanged(WebView view, int newProgress) {
+                super.onProgressChanged(view, newProgress);
+                showWebView(newProgress == 100);
+                showProgressBar(newProgress != 100);
+                WXLogUtils.v("tag", "onPageProgressChanged " + newProgress);
+            }
+
+            @Override
+            public void onReceivedTitle(WebView view, String title) {
+                super.onReceivedTitle(view, title);
+                if (mOnPageListener != null) {
+                    mOnPageListener.onReceivedTitle(view.getTitle());
+                }
+            }
+
+            @Override
+            public boolean onJsPrompt(WebView view, String url, String text, String defaultValue, JsPromptResult result) {
+                Uri uri = Uri.parse(text);
+                String scheme = uri.getScheme();
+                if (TextUtils.equals(scheme, BRIDGE_NAME)) {
+                    if (TextUtils.equals(uri.getAuthority(), "postMessage")) {
+                        String message = uri.getQueryParameter("message");
+                        String targetOrigin = uri.getQueryParameter("targetOrigin");
+                        onMessage(message, targetOrigin);
+                        result.confirm("success");
+                    } else {
+                        result.confirm("fail");
+                    }
+                    return true;
+                }
+                return super.onJsPrompt(view, url, text, defaultValue, result);
+            }
+        });
+        if (!DOWNGRADE_JS_INTERFACE) {
+            wv.addJavascriptInterface(new Object() {
+                @JavascriptInterface
+                public void postMessage(String message, String targetOrigin) {
+                    onMessage(message, targetOrigin);
+                }
+            }, BRIDGE_NAME);
+        }
+    }
+
+    private void onMessage(String message, String targetOrigin) {
+        if (message != null && targetOrigin != null && mOnMessageListener != null) {
+            try {
+                Map<String, Object> initData = new HashMap<>();
+                initData.put("data", JSON.parse(message));
+                initData.put("origin", targetOrigin);
+                initData.put("type", "message");
+                Message threadMessage = new Message();
+                threadMessage.what = POST_MESSAGE;
+                threadMessage.obj = initData;
+                mMessageHandler.sendMessage(threadMessage);
+            } catch (JSONException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private void evaluateJS(String jsStr) {
+        if (SDK_VERSION < 19) {
+            mWebView.loadUrl(jsStr);
+        } else {
+            mWebView.evaluateJavascript(jsStr, null);
+        }
+    }
+
+    private static class MessageHandler extends Handler {
+        private final WeakReference<WXWebView> mWv;
+
+        private MessageHandler(WXWebView wv) {
+            mWv = new WeakReference<>(wv);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            switch (msg.what) {
+                case POST_MESSAGE:
+                    if (mWv.get() != null && mWv.get().mOnMessageListener != null) {
+                        mWv.get().mOnMessageListener.onMessage((Map<String, Object>) msg.obj);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderCorner.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderCorner.java
new file mode 100644
index 0000000..a997132
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderCorner.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.NonNull;
+import org.apache.weex.base.FloatUtil;
+
+abstract class BorderCorner {
+
+  final static float SWEEP_ANGLE = 45;
+  private float mCornerRadius = 0.0f;
+  private float mPreBorderWidth = 0.0f;
+  private float mPostBorderWidth = 0.0f;
+  private RectF mBorderBox;
+  protected float mAngleBisector;
+
+  /**
+   * Tell whether this corner has a rounded inner corner.
+   * If a corner has a rounded inner corner, it has an outer corner as well.
+   */
+  private boolean hasInnerCorner = false;
+
+  /**
+   * Tell whether this corner has a rounded outer corner.
+   */
+  private boolean hasOuterCorner = false;
+
+  private float mOvalLeft, mOvalTop, mOvalRight, mOvalBottom;
+
+  private float mRoundCornerStartX, mRoundCornerStartY;
+  private float mRoundCornerEndX, mRoundCornerEndY;
+
+  BorderCorner() {
+  }
+
+  final void set(float cornerRadius, float preBorderWidth, float postBorderWidth,
+                 @NonNull RectF borderBox, float angleBisector) {
+    boolean dirty = !FloatUtil.floatsEqual(mCornerRadius, cornerRadius)
+        || !FloatUtil.floatsEqual(mPreBorderWidth, preBorderWidth)
+        || !FloatUtil.floatsEqual(mPostBorderWidth, postBorderWidth)
+        || !FloatUtil.floatsEqual(mAngleBisector, angleBisector)
+        || (null != mBorderBox && mBorderBox.equals(borderBox));
+
+    if (dirty) {
+      mCornerRadius = cornerRadius;
+      mPreBorderWidth = preBorderWidth;
+      mPostBorderWidth = postBorderWidth;
+      mBorderBox = borderBox;
+      mAngleBisector = angleBisector;
+
+      hasOuterCorner = mCornerRadius > 0 && !FloatUtil.floatsEqual(0, mCornerRadius);
+
+      hasInnerCorner = (hasOuterCorner
+          && (getPreBorderWidth() >= 0)
+          && (getPostBorderWidth() >= 0)
+          && (getOuterCornerRadius() > getPreBorderWidth())
+          && (getOuterCornerRadius() > getPostBorderWidth()));
+
+      if (hasOuterCorner) {
+        prepareOval();
+      }
+      prepareRoundCorner();
+    }
+  }
+
+  /** Build oval data */
+  abstract protected void prepareOval();
+
+  /** Build corner data */
+  abstract protected void prepareRoundCorner();
+
+  public final void drawRoundedCorner(@NonNull Canvas canvas, @NonNull Paint paint, float startAngle) {
+    if (this.hasOuterCorner()) {
+      /*Due to the problem of hardware-acceleration, border-radius in some case will not
+       be rendered if Path.addArc used instead and the following condition met.
+       1. hardware-acceleration enabled
+       2. System version is Android 4.1
+       3. Screen width is 720px.
+       http://dotwe.org/weex/421b9ad09fde51c0b49bb56b37fcf955
+      */
+      if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+        canvas.drawArc(mOvalLeft, mOvalTop, mOvalRight, mOvalBottom, startAngle, BorderCorner.SWEEP_ANGLE, false,
+            paint);
+      } else {
+        canvas.drawArc(new RectF(mOvalLeft, mOvalTop, mOvalRight, mOvalBottom), startAngle, BorderCorner.SWEEP_ANGLE,
+            false, paint);
+      }
+    } else {
+      canvas.drawLine(getRoundCornerStartX(), getRoundCornerStartY(), getRoundCornerEndX(), getRoundCornerEndY(),
+          paint);
+    }
+  }
+
+
+  public final float getRoundCornerStartX() {
+    return mRoundCornerStartX;
+  }
+
+  final void setRoundCornerStartX(float roundCornerStartX) {
+    this.mRoundCornerStartX = roundCornerStartX;
+  }
+
+  public final float getRoundCornerStartY() {
+    return mRoundCornerStartY;
+  }
+
+  final void setRoundCornerStartY(float roundCornerStartY) {
+    this.mRoundCornerStartY = roundCornerStartY;
+  }
+
+  public final float getRoundCornerEndX() {
+    return mRoundCornerEndX;
+  }
+
+  final void setRoundCornerEndX(float mRoundCornerEndX) {
+    this.mRoundCornerEndX = mRoundCornerEndX;
+  }
+
+  public final float getRoundCornerEndY() {
+    return mRoundCornerEndY;
+  }
+
+  final void setRoundCornerEndY(float mRoundCornerEndY) {
+    this.mRoundCornerEndY = mRoundCornerEndY;
+  }
+
+  final void setOvalLeft(float mOvalLeft) {
+    this.mOvalLeft = mOvalLeft;
+  }
+
+  final void setOvalTop(float mOvalTop) {
+    this.mOvalTop = mOvalTop;
+  }
+
+  final void setOvalRight(float mOvalRight) {
+    this.mOvalRight = mOvalRight;
+  }
+
+  final void setOvalBottom(float mOvalBottom) {
+    this.mOvalBottom = mOvalBottom;
+  }
+
+  /**
+   * Tell whether this corner has a rounded inner corner.
+   * If a corner has a rounded inner corner, it has an outer corner as well.
+   * @return true for a rounded inner corner, otherwise false.
+   */
+  boolean hasInnerCorner() {
+    return hasInnerCorner;
+  }
+
+  /**
+   * Tell whether this corner has a rounded outer corner.
+   * @return true for a rounded outer corner, otherwise false.
+   */
+  boolean hasOuterCorner() {
+    return hasOuterCorner;
+  }
+
+  protected final float getPreBorderWidth() {
+    return mPreBorderWidth;
+  }
+
+  protected final float getPostBorderWidth() {
+    return mPostBorderWidth;
+  }
+
+  protected final float getOuterCornerRadius() {
+    return mCornerRadius;
+  }
+
+  protected final float getAngleBisectorDegree(){
+    return mAngleBisector;
+  }
+
+  protected final RectF getBorderBox() {
+    return mBorderBox;
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderDrawable.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderDrawable.java
new file mode 100644
index 0000000..72b21e0
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderDrawable.java
@@ -0,0 +1,496 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.SparseIntArray;
+import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.dom.CSSShorthand.CORNER;
+import org.apache.weex.dom.CSSShorthand.EDGE;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXViewUtils;
+import org.apache.weex.ui.component.WXComponent;
+
+import static org.apache.weex.dom.CSSShorthand.CORNER.ALL;
+import static org.apache.weex.dom.CSSShorthand.CORNER.BORDER_BOTTOM_LEFT;
+import static org.apache.weex.dom.CSSShorthand.CORNER.BORDER_BOTTOM_RIGHT;
+import static org.apache.weex.dom.CSSShorthand.CORNER.BORDER_TOP_LEFT;
+import static org.apache.weex.dom.CSSShorthand.CORNER.BORDER_TOP_RIGHT;
+
+/**
+ * A subclass of
+ * {@link Drawable} used for background of {@link WXComponent}.
+ * It supports drawing background color and borders (including rounded borders) by providing a react
+ * friendly API (setter for each of those properties). The implementation tries to allocate as few
+ * objects as possible depending on which properties are set. E.g. for views with rounded
+ * background/borders we allocate {@code mPathForBorderDrawn} and {@code mTempRectForBorderRadius}.
+ * In case when view have a rectangular borders we allocate {@code mBorderWidthResult} and similar.
+ * When only background color is set we won't allocate any extra/unnecessary objects.
+ */
+public class BorderDrawable extends Drawable {
+
+  public static final int BORDER_TOP_LEFT_RADIUS = 0;
+  public static final int BORDER_TOP_RIGHT_RADIUS = 1;
+  public static final int BORDER_BOTTOM_RIGHT_RADIUS = 2;
+  public static final int BORDER_BOTTOM_LEFT_RADIUS = 3;
+  public static final int BORDER_RADIUS_ALL = 5;
+  static final int DEFAULT_BORDER_COLOR = Color.BLACK;
+  static final float DEFAULT_BORDER_WIDTH = 0;
+  private static final BorderStyle DEFAULT_BORDER_STYLE = BorderStyle.SOLID;
+  private static final String TAG = "Border";
+  private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+  private static BorderStyle[] sBorderStyle = BorderStyle.values();
+
+  private
+  @Nullable
+  CSSShorthand<EDGE> mBorderWidth;
+  private
+  @Nullable
+  CSSShorthand<CORNER> mBorderRadius;
+  private
+  @Nullable
+  CSSShorthand<CORNER> mOverlappingBorderRadius;
+  private
+  @Nullable
+  SparseIntArray mBorderColor;
+  private
+  @Nullable
+  SparseIntArray mBorderStyle;
+
+  private
+  @Nullable
+  Path mPathForBorderOutline;
+  private boolean mNeedUpdatePath = false;
+  private int mColor = Color.TRANSPARENT;
+  /**
+   * set background-image linear-gradient
+   */
+  private Shader mShader = null;
+  private int mAlpha = 255;
+
+  private TopLeftCorner mTopLeftCorner;
+  private TopRightCorner mTopRightCorner;
+  private BottomRightCorner mBottomRightCorner;
+  private BottomLeftCorner mBottomLeftCorner;
+
+  private final BorderEdge mBorderEdge = new BorderEdge();
+
+  private RectF mRectBounds;
+
+  public BorderDrawable() {
+  }
+
+  @Override
+  public void draw(@NonNull Canvas canvas) {
+    canvas.save();
+    updateBorderOutline();
+    //Shader uses alpha as well.
+    mPaint.setAlpha(255);
+    if (mPathForBorderOutline != null) {
+      int useColor = WXViewUtils.multiplyColorAlpha(mColor, mAlpha);
+      if (mShader != null) {
+        mPaint.setShader(mShader);
+        mPaint.setStyle(Paint.Style.FILL);
+        canvas.drawPath(mPathForBorderOutline, mPaint);
+        mPaint.setShader(null);
+      } else if ((useColor >>> 24) != 0) {
+        mPaint.setColor(useColor);
+        mPaint.setStyle(Paint.Style.FILL);
+        canvas.drawPath(mPathForBorderOutline, mPaint);
+        mPaint.setShader(null);
+      }
+    }
+    mPaint.setStyle(Paint.Style.STROKE);
+    mPaint.setStrokeJoin(Paint.Join.ROUND);
+    drawBorders(canvas);
+    mPaint.setShader(null);
+    canvas.restore();
+  }
+
+  @Override
+  protected void onBoundsChange(Rect bounds) {
+    super.onBoundsChange(bounds);
+    mNeedUpdatePath = true;
+  }
+
+  @Override
+  public void setAlpha(int alpha) {
+    if (alpha != mAlpha) {
+      mAlpha = alpha;
+      invalidateSelf();
+    }
+  }
+
+  @Override
+  public int getAlpha() {
+    return mAlpha;
+  }
+
+  /**
+   * Do not support Color Filter
+   */
+  @Override
+  public void setColorFilter(ColorFilter cf) {
+
+  }
+
+  @Override
+  public int getOpacity() {
+    return mShader != null ? PixelFormat.OPAQUE :
+            WXViewUtils.getOpacityFromColor(WXViewUtils.multiplyColorAlpha(mColor, mAlpha));
+  }
+
+  /* Android's elevation implementation requires this to be implemented to know where to draw the
+ shadow. */
+  @Override
+  public void getOutline(@NonNull Outline outline) {
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+      if (mPathForBorderOutline == null) {
+        mNeedUpdatePath = true;
+      }
+      updateBorderOutline();
+      outline.setConvexPath(mPathForBorderOutline);
+    }
+  }
+
+  public void setBorderWidth(CSSShorthand.EDGE edge, float width) {
+    if (mBorderWidth == null) {
+      mBorderWidth = new CSSShorthand<>();
+    }
+    if (mBorderWidth.get(edge) != width) {
+      mBorderWidth.set(edge, width);
+      mNeedUpdatePath = true;
+      invalidateSelf();
+    }
+  }
+
+  float getBorderWidth(CSSShorthand.EDGE edge) {
+    return mBorderWidth.get(edge);
+  }
+
+  public void setBorderRadius(CORNER position, float radius) {
+    if (mBorderRadius == null) {
+      mBorderRadius = new CSSShorthand<>();
+    }
+    if (mBorderRadius.get(position) != radius ||
+        (position == ALL &&
+            (radius != mBorderRadius.get(BORDER_TOP_LEFT) ||
+            radius != mBorderRadius.get(BORDER_TOP_RIGHT) ||
+            radius != mBorderRadius.get(BORDER_BOTTOM_RIGHT) ||
+            radius != mBorderRadius.get(BORDER_BOTTOM_LEFT)))) {
+      mBorderRadius.set(position, radius);
+      mNeedUpdatePath = true;
+      invalidateSelf();
+    }
+  }
+
+  public
+  @NonNull
+  float[] getBorderRadius(RectF borderBox) {
+    prepareBorderRadius(borderBox);
+    if (mOverlappingBorderRadius == null) {
+      mOverlappingBorderRadius = new CSSShorthand<>();
+    }
+    float topLeftRadius = mOverlappingBorderRadius.get(BORDER_TOP_LEFT);
+    float topRightRadius = mOverlappingBorderRadius.get(BORDER_TOP_RIGHT);
+    float bottomRightRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_RIGHT);
+    float bottomLeftRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_LEFT);
+    return new float[]{topLeftRadius, topLeftRadius,
+            topRightRadius, topRightRadius,
+            bottomRightRadius, bottomRightRadius,
+            bottomLeftRadius, bottomLeftRadius};
+  }
+
+  public
+  @NonNull
+  float[] getBorderInnerRadius(RectF borderBox) {
+    prepareBorderRadius(borderBox);
+    if (mOverlappingBorderRadius == null) {
+      mOverlappingBorderRadius = new CSSShorthand<>();
+    }
+    float topLeftRadius = mOverlappingBorderRadius.get(BORDER_TOP_LEFT);
+    float topRightRadius = mOverlappingBorderRadius.get(BORDER_TOP_RIGHT);
+    float bottomRightRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_RIGHT);
+    float bottomLeftRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_LEFT);
+    if (null != mBorderWidth) {
+      topLeftRadius = Math.max(topLeftRadius - mBorderWidth.get(EDGE.TOP), 0);
+      topRightRadius = Math.max(topRightRadius - mBorderWidth.get(EDGE.TOP), 0);
+      bottomRightRadius = Math.max(bottomRightRadius - mBorderWidth.get(EDGE.BOTTOM), 0);
+      bottomLeftRadius = Math.max(bottomLeftRadius - mBorderWidth.get(EDGE.BOTTOM), 0);
+    }
+    return new float[] {topLeftRadius, topLeftRadius,
+        topRightRadius, topRightRadius,
+        bottomRightRadius, bottomRightRadius,
+        bottomLeftRadius, bottomLeftRadius};
+  }
+
+  public void setBorderColor(CSSShorthand.EDGE edge, int color) {
+    if (mBorderColor == null) {
+      mBorderColor = new SparseIntArray(5);
+      mBorderColor.put(CSSShorthand.EDGE.ALL.ordinal(), DEFAULT_BORDER_COLOR);
+    }
+    if (getBorderColor(edge) != color) {
+      BorderUtil.updateSparseArray(mBorderColor, edge.ordinal(), color);
+      invalidateSelf();
+    }
+  }
+
+  int getBorderColor(CSSShorthand.EDGE edge) {
+    return BorderUtil.fetchFromSparseArray(mBorderColor, edge.ordinal(), DEFAULT_BORDER_COLOR);
+  }
+
+  public void setBorderStyle(CSSShorthand.EDGE edge, @NonNull String style) {
+    if (mBorderStyle == null) {
+      mBorderStyle = new SparseIntArray(5);
+      mBorderStyle.put(CSSShorthand.EDGE.ALL.ordinal(), DEFAULT_BORDER_STYLE.ordinal());
+    }
+    try {
+      int borderStyle = BorderStyle.valueOf(style.toUpperCase(Locale.US)).ordinal();
+      if (getBorderStyle(edge) != borderStyle) {
+        BorderUtil.updateSparseArray(mBorderStyle, edge.ordinal(), borderStyle);
+        invalidateSelf();
+      }
+    } catch (IllegalArgumentException e) {
+      WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
+    }
+  }
+
+  int getBorderStyle(CSSShorthand.EDGE edge) {
+    return BorderUtil.fetchFromSparseArray(mBorderStyle, edge.ordinal(), BorderStyle.SOLID.ordinal());
+  }
+
+  public int getColor() {
+    return mColor;
+  }
+
+  public void setColor(int color) {
+    mColor = color;
+    invalidateSelf();
+  }
+
+  public void setImage(Shader shader) {
+    mShader = shader;
+    invalidateSelf();
+  }
+
+  public boolean hasImage() {
+    return mShader != null;
+  }
+
+  public boolean isRounded() {
+    return mBorderRadius != null &&
+            (mBorderRadius.get(BORDER_TOP_LEFT) != 0 ||
+                mBorderRadius.get(BORDER_TOP_RIGHT) != 0 ||
+                mBorderRadius.get(BORDER_BOTTOM_RIGHT) != 0 ||
+                mBorderRadius.get(BORDER_BOTTOM_LEFT) != 0);
+  }
+
+  public
+  @NonNull
+  Path getContentPath(@NonNull RectF borderBox) {
+    Path contentClip = new Path();
+    prepareBorderPath(0, 0, 0, 0, borderBox, contentClip);
+    return contentClip;
+  }
+
+  private void updateBorderOutline() {
+    if (mNeedUpdatePath) {
+      mNeedUpdatePath = false;
+      if (mPathForBorderOutline == null) {
+        mPathForBorderOutline = new Path();
+      }
+      mPathForBorderOutline.reset();
+      prepareBorderPath(0, 0, 0, 0, new RectF(getBounds()), mPathForBorderOutline);
+    }
+  }
+
+  private void prepareBorderPath(int topPadding,
+                                 int rightPadding,
+                                 int bottomPadding,
+                                 int leftPadding,
+                                 @NonNull RectF rectF,
+                                 @NonNull Path path) {
+    if (mBorderRadius != null) {
+      prepareBorderRadius(rectF);
+      if (mOverlappingBorderRadius == null) {
+        mOverlappingBorderRadius = new CSSShorthand<>();
+      }
+      float topLeftRadius = mOverlappingBorderRadius.get(BORDER_TOP_LEFT);
+      float topRightRadius = mOverlappingBorderRadius.get(BORDER_TOP_RIGHT);
+      float bottomRightRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_RIGHT);
+      float bottomLeftRadius = mOverlappingBorderRadius.get(BORDER_BOTTOM_LEFT);
+      path.addRoundRect(
+              rectF,
+              new float[]{
+                      topLeftRadius - leftPadding,
+                      topLeftRadius - topPadding,
+                      topRightRadius - rightPadding,
+                      topRightRadius - topPadding,
+                      bottomRightRadius - rightPadding,
+                      bottomRightRadius - bottomPadding,
+                      bottomLeftRadius - leftPadding,
+                      bottomLeftRadius - bottomPadding
+              },
+              Path.Direction.CW);
+    } else {
+      path.addRect(rectF, Path.Direction.CW);
+    }
+  }
+
+  /**
+   * Process overlapping curve according to https://www.w3.org/TR/css3-background/#corner-overlap .
+   */
+  private void prepareBorderRadius(@NonNull RectF borderBox) {
+    if (mBorderRadius != null) {
+      float factor = getScaleFactor(borderBox);
+      if (mOverlappingBorderRadius == null) {
+        mOverlappingBorderRadius = new CSSShorthand<>();
+      }
+      if (!Float.isNaN(factor) && factor < 1) {
+        mOverlappingBorderRadius.set(BORDER_TOP_LEFT,
+            mBorderRadius.get(BORDER_TOP_LEFT) * factor);
+        mOverlappingBorderRadius.set(BORDER_TOP_RIGHT,
+            mBorderRadius.get(BORDER_TOP_RIGHT) * factor);
+        mOverlappingBorderRadius.set(BORDER_BOTTOM_RIGHT,
+            mBorderRadius.get(BORDER_BOTTOM_RIGHT) * factor);
+        mOverlappingBorderRadius.set(BORDER_BOTTOM_LEFT,
+            mBorderRadius.get(BORDER_BOTTOM_LEFT) * factor);
+      } else {
+        mOverlappingBorderRadius.set(BORDER_TOP_LEFT,
+            mBorderRadius.get(BORDER_TOP_LEFT));
+        mOverlappingBorderRadius.set(BORDER_TOP_RIGHT,
+            mBorderRadius.get(BORDER_TOP_RIGHT));
+        mOverlappingBorderRadius.set(BORDER_BOTTOM_RIGHT,
+            mBorderRadius.get(BORDER_BOTTOM_RIGHT));
+        mOverlappingBorderRadius.set(BORDER_BOTTOM_LEFT,
+            mBorderRadius.get(BORDER_BOTTOM_LEFT));
+      }
+    }
+  }
+
+  private float getScaleFactor(@NonNull RectF borderBox) {
+    final float topRadius = mBorderRadius.get(BORDER_TOP_LEFT)
+            + mBorderRadius.get(BORDER_TOP_RIGHT);
+    final float rightRadius = mBorderRadius.get(BORDER_TOP_RIGHT)
+            + mBorderRadius.get(BORDER_BOTTOM_RIGHT);
+    final float bottomRadius = mBorderRadius.get(BORDER_BOTTOM_RIGHT)
+            + mBorderRadius.get(BORDER_BOTTOM_LEFT);
+    final float leftRadius = mBorderRadius.get(BORDER_BOTTOM_LEFT)
+            + mBorderRadius.get(BORDER_TOP_LEFT);
+    List<Float> factors = new ArrayList<>(4);
+    updateFactor(factors, borderBox.width(), topRadius);
+    updateFactor(factors, borderBox.height(), rightRadius);
+    updateFactor(factors, borderBox.width(), bottomRadius);
+    updateFactor(factors, borderBox.height(), leftRadius);
+    float factor;
+    if (factors.isEmpty()) {
+      factor = Float.NaN;
+    } else {
+      factor = Collections.min(factors);
+    }
+    return factor;
+  }
+
+  private void updateFactor(@NonNull List<Float> list, float numerator, float denominator) {
+    if (denominator != 0) {
+      list.add(numerator / denominator);
+    }
+  }
+
+  private void drawBorders(Canvas canvas) {
+    if (mRectBounds == null) {
+      mRectBounds = new RectF(getBounds());
+    } else {
+      mRectBounds.set(getBounds());
+    }
+
+    if (mBorderWidth == null)
+      return;
+
+    final float leftBorderWidth = mBorderWidth.get(EDGE.LEFT);
+    final float topBorderWidth = mBorderWidth.get(EDGE.TOP);
+    final float bottomBorderWidth = mBorderWidth.get(EDGE.BOTTOM);
+    final float rightBorderWidth = mBorderWidth.get(EDGE.RIGHT);
+
+    if (mTopLeftCorner == null) {
+      mTopLeftCorner = new TopLeftCorner();
+    }
+    mTopLeftCorner.set(getBorderRadius(BORDER_TOP_LEFT), leftBorderWidth, topBorderWidth, mRectBounds);
+    if (mTopRightCorner == null) {
+      mTopRightCorner = new TopRightCorner();
+    }
+    mTopRightCorner.set(getBorderRadius(BORDER_TOP_RIGHT), topBorderWidth, rightBorderWidth, mRectBounds);
+    if (mBottomRightCorner == null) {
+      mBottomRightCorner = new BottomRightCorner();
+    }
+    mBottomRightCorner.set(getBorderRadius(BORDER_BOTTOM_RIGHT), rightBorderWidth, bottomBorderWidth, mRectBounds);
+    if (mBottomLeftCorner == null) {
+      mBottomLeftCorner = new BottomLeftCorner();
+    }
+    mBottomLeftCorner.set(getBorderRadius(BORDER_BOTTOM_LEFT), bottomBorderWidth, leftBorderWidth, mRectBounds);
+
+    drawOneSide(canvas, mBorderEdge.set(mTopLeftCorner, mTopRightCorner, topBorderWidth, EDGE.TOP));
+    drawOneSide(canvas, mBorderEdge.set(mTopRightCorner, mBottomRightCorner, rightBorderWidth, EDGE.RIGHT));
+    drawOneSide(canvas, mBorderEdge.set(mBottomRightCorner, mBottomLeftCorner, bottomBorderWidth, EDGE.BOTTOM));
+    drawOneSide(canvas, mBorderEdge.set(mBottomLeftCorner, mTopLeftCorner, leftBorderWidth, EDGE.LEFT));
+  }
+
+  private float getBorderRadius(CORNER position) {
+    if (null != mOverlappingBorderRadius) {
+      return mOverlappingBorderRadius.get(position);
+    } else {
+      return 0.0f;
+    }
+  }
+
+  private void drawOneSide(Canvas canvas, @NonNull BorderEdge borderEdge) {
+    if (0 != borderEdge.getBorderWidth()) {
+      preparePaint(borderEdge.getEdge());
+      borderEdge.drawEdge(canvas, mPaint);
+    }
+  }
+
+  private void preparePaint(CSSShorthand.EDGE edge) {
+    final float borderWidth = mBorderWidth.get(edge);
+    final int color = WXViewUtils.multiplyColorAlpha(getBorderColor(edge), mAlpha);
+    final BorderStyle borderStyle = sBorderStyle[getBorderStyle(edge)];
+    final Shader shader = borderStyle.getLineShader(borderWidth, color, edge);
+    mPaint.setShader(shader);
+    mPaint.setColor(color);
+    mPaint.setStrokeCap(Paint.Cap.ROUND);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderEdge.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderEdge.java
new file mode 100644
index 0000000..8d4d17e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderEdge.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.support.annotation.NonNull;
+import org.apache.weex.dom.CSSShorthand;
+
+/**
+ * Edge for border. Every border has four edges, and each edge has a previous corner and a post
+ * corner.
+ */
+class BorderEdge {
+
+  private
+  @NonNull
+  BorderCorner mPreCorner;
+  private
+  @NonNull
+  BorderCorner mPostCorner;
+
+  private CSSShorthand.EDGE mEdge;
+  private float mBorderWidth;
+
+  BorderEdge() {
+  }
+
+  BorderEdge set(@NonNull BorderCorner preCorner, @NonNull BorderCorner postCorner,
+                 float borderWidth, CSSShorthand.EDGE edge) {
+    mPreCorner = preCorner;
+    mPostCorner = postCorner;
+    mBorderWidth = borderWidth;
+    mEdge = edge;
+    return this;
+  }
+
+  /**
+   * Draw the edge on the canvas with the specified paint.
+   * @param canvas the canvas where the edge will be drawn.
+   * @param paint the paint which is used to draw.
+   */
+  void drawEdge(@NonNull Canvas canvas, @NonNull Paint paint) {
+    paint.setStrokeWidth(mBorderWidth);
+
+    mPreCorner.drawRoundedCorner(canvas, paint, mPreCorner.getAngleBisectorDegree());
+
+    paint.setStrokeWidth(mBorderWidth);
+
+    final float lineStartX = mPreCorner.getRoundCornerEndX();
+    final float lineStartY = mPreCorner.getRoundCornerEndY();
+
+    final float lineEndX = mPostCorner.getRoundCornerStartX();
+    final float lineEndY = mPostCorner.getRoundCornerStartY();
+
+    canvas.drawLine(lineStartX, lineStartY, lineEndX, lineEndY, paint);
+
+    mPostCorner.drawRoundedCorner(canvas, paint, mPostCorner.getAngleBisectorDegree() - BorderCorner.SWEEP_ANGLE);
+  }
+
+  /**
+   * The index of the edge
+   * @return index of edge. May be one of
+   */
+  public CSSShorthand.EDGE getEdge() {
+    return mEdge;
+  }
+
+  public float getBorderWidth() {
+    return mBorderWidth;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderRadiusType.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderRadiusType.java
new file mode 100644
index 0000000..955991b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderRadiusType.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.SOURCE)
+@IntDef({
+    BorderDrawable.BORDER_TOP_LEFT_RADIUS,
+    BorderDrawable.BORDER_TOP_RIGHT_RADIUS,
+    BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS,
+    BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS,
+    BorderDrawable.BORDER_RADIUS_ALL})
+public @interface BorderRadiusType {
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderStyle.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderStyle.java
new file mode 100644
index 0000000..c31d060
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderStyle.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.PathEffect;
+import android.graphics.Shader;
+import android.support.annotation.Nullable;
+import org.apache.weex.dom.CSSShorthand;
+
+enum BorderStyle {
+  SOLID,
+  DASHED,
+  DOTTED;
+
+  /**
+   * Use {@link LinearGradient} to replace {@link PathEffect}
+   * for implementing {@link #DASHED} or {@link #DASHED}
+   * @param borderWidth width of the edge
+   * @param borderColor color of the edge
+   * @param edge the index of the ede. See {@link CSSShorthand}
+   * @return An object of {@link LinearGradient} without color transitions for {@link #DOTTED}
+   * or {@link #DASHED}, null otherwise
+   */
+  @Nullable
+  Shader getLineShader(float borderWidth, int borderColor, CSSShorthand.EDGE edge) {
+    switch (this) {
+      case DOTTED:
+        if (edge == CSSShorthand.EDGE.LEFT || edge == CSSShorthand.EDGE.RIGHT) {
+          return new LinearGradient(0, 0, 0, borderWidth * 2, new int[]{borderColor, Color
+                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
+        } else if (edge == CSSShorthand.EDGE.TOP || edge == CSSShorthand.EDGE.BOTTOM) {
+          return new LinearGradient(0, 0, borderWidth * 2, 0, new int[]{borderColor, Color
+                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
+        }
+      case DASHED:
+        if (edge == CSSShorthand.EDGE.LEFT || edge == CSSShorthand.EDGE.RIGHT) {
+          return new LinearGradient(0, 0, 0, borderWidth * 6, new int[]{borderColor, Color
+                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
+        } else if (edge == CSSShorthand.EDGE.TOP || edge == CSSShorthand.EDGE.BOTTOM) {
+          return new LinearGradient(0, 0, borderWidth * 6, 0, new int[]{borderColor, Color
+                  .TRANSPARENT}, new float[]{0.5f, 0.5f}, Shader.TileMode.REPEAT);
+        }
+      default:
+        return null;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderUtil.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderUtil.java
new file mode 100644
index 0000000..8aad832
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BorderUtil.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.SparseIntArray;
+import org.apache.weex.dom.CSSShorthand;
+
+class BorderUtil {
+
+  static int fetchFromSparseArray(@Nullable SparseIntArray array, int position, int fallback) {
+    return array == null ? fallback :
+            array.get(position, array.get(CSSShorthand.EDGE.ALL.ordinal()));
+  }
+
+  static void updateSparseArray(@NonNull SparseIntArray array, int position, int value) {
+    if (position == CSSShorthand.EDGE.ALL.ordinal()) {
+      array.put(CSSShorthand.EDGE.ALL.ordinal(), value);
+      array.put(CSSShorthand.EDGE.TOP.ordinal(), value);
+      array.put(CSSShorthand.EDGE.LEFT.ordinal(), value);
+      array.put(CSSShorthand.EDGE.RIGHT.ordinal(), value);
+      array.put(CSSShorthand.EDGE.BOTTOM.ordinal(), value);
+    } else {
+      array.put(position, value);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BottomLeftCorner.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BottomLeftCorner.java
new file mode 100644
index 0000000..79d964e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BottomLeftCorner.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+
+class BottomLeftCorner extends BorderCorner {
+
+  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
+    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 135);
+  }
+
+  @Override
+  protected void prepareOval() {
+    if (hasInnerCorner()) {
+      setOvalLeft(getPostBorderWidth() / 2);
+      setOvalTop(getBorderBox().height() - (2 * getOuterCornerRadius() - getPreBorderWidth() / 2));
+      setOvalRight(2 * getOuterCornerRadius() - getPostBorderWidth() / 2);
+      setOvalBottom(getBorderBox().height() - getPreBorderWidth() / 2);
+    } else {
+      setOvalLeft(getOuterCornerRadius() / 2);
+      setOvalTop(getBorderBox().height() - 1.5f * getOuterCornerRadius());
+      setOvalRight(1.5f * getOuterCornerRadius());
+      setOvalBottom(getBorderBox().height() - getOuterCornerRadius() / 2);
+    }
+  }
+
+  @Override
+  protected void prepareRoundCorner() {
+    if (hasOuterCorner()) {
+      setRoundCornerStartX(getOuterCornerRadius());
+      setRoundCornerStartY(getBorderBox().height() - getPreBorderWidth() / 2);
+
+      setRoundCornerEndX(getPostBorderWidth() / 2);
+      setRoundCornerEndY(getBorderBox().height() - getOuterCornerRadius());
+    } else {
+      final float x = getPostBorderWidth() / 2;
+      final float y = getBorderBox().height() - getPreBorderWidth() / 2;
+
+      setRoundCornerStartX(x);
+      setRoundCornerStartY(y);
+
+      setRoundCornerEndX(x);
+      setRoundCornerEndY(y);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/BottomRightCorner.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BottomRightCorner.java
new file mode 100644
index 0000000..0d30912
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/BottomRightCorner.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+
+class BottomRightCorner extends BorderCorner {
+
+  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
+    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 45);
+  }
+
+  @Override
+  protected void prepareOval() {
+    if (hasInnerCorner()) {
+      setOvalLeft(getBorderBox().width() - (2 * getOuterCornerRadius() - getPreBorderWidth() / 2));
+      setOvalTop(getBorderBox().height() - (2 * getOuterCornerRadius() - getPostBorderWidth() / 2));
+      setOvalRight(getBorderBox().width() - (getPreBorderWidth() / 2));
+      setOvalBottom(getBorderBox().height() - (getPostBorderWidth() / 2));
+    } else {
+      setOvalLeft(getBorderBox().width() - 1.5f * getOuterCornerRadius());
+      setOvalTop(getBorderBox().height() - 1.5f * getOuterCornerRadius());
+      setOvalRight(getBorderBox().width() - getOuterCornerRadius() / 2);
+      setOvalBottom(getBorderBox().height() - getOuterCornerRadius() / 2);
+    }
+  }
+
+  @Override
+  protected void prepareRoundCorner() {
+    if (hasOuterCorner()) {
+      setRoundCornerStartX(getBorderBox().width() - getPreBorderWidth() / 2);
+      setRoundCornerStartY(getBorderBox().height() - getOuterCornerRadius());
+
+      setRoundCornerEndX(getBorderBox().width() - getOuterCornerRadius());
+      setRoundCornerEndY(getBorderBox().height() - getPostBorderWidth() / 2);
+    } else {
+      final float x = getBorderBox().width() - getPreBorderWidth() / 2;
+      final float y = getBorderBox().height() - getPostBorderWidth() / 2;
+
+      setRoundCornerStartX(x);
+      setRoundCornerStartY(y);
+
+      setRoundCornerEndX(x);
+      setRoundCornerEndY(y);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/TopLeftCorner.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/TopLeftCorner.java
new file mode 100644
index 0000000..5d9422d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/TopLeftCorner.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+
+class TopLeftCorner extends BorderCorner {
+
+  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
+    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 225);
+  }
+
+  @Override
+  protected void prepareOval() {
+    if (hasInnerCorner()) {
+      setOvalLeft(getPreBorderWidth() / 2);
+      setOvalTop(getPostBorderWidth() / 2);
+      setOvalRight(2 * getOuterCornerRadius() - getPreBorderWidth() / 2);
+      setOvalBottom(2 * getOuterCornerRadius() - getPostBorderWidth() / 2);
+    } else {
+      setOvalLeft(getOuterCornerRadius() / 2);
+      setOvalTop(getOuterCornerRadius() / 2);
+      setOvalRight(getOuterCornerRadius() * 1.5f);
+      setOvalBottom(getOuterCornerRadius() * 1.5f);
+    }
+  }
+
+  @Override
+  protected void prepareRoundCorner() {
+    if (hasOuterCorner()) {
+      setRoundCornerStartX(getPreBorderWidth() / 2);
+      setRoundCornerStartY(getOuterCornerRadius());
+
+      setRoundCornerEndX(getOuterCornerRadius());
+      setRoundCornerEndY(getPostBorderWidth() / 2);
+    } else {
+      final float x = getPreBorderWidth() / 2;
+      final float y = getPostBorderWidth() / 2;
+
+      setRoundCornerStartX(x);
+      setRoundCornerStartY(y);
+
+      setRoundCornerEndX(x);
+      setRoundCornerEndY(y);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/border/TopRightCorner.java b/android/sdk/src/main/java/org/apache/weex/ui/view/border/TopRightCorner.java
new file mode 100644
index 0000000..58b8384
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/border/TopRightCorner.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.border;
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+
+class TopRightCorner extends BorderCorner {
+
+  void set(float cornerRadius, float preBorderWidth, float postBorderWidth, @NonNull RectF borderBox) {
+    set(cornerRadius, preBorderWidth, postBorderWidth, borderBox, 315);
+  }
+
+  @Override
+  protected void prepareOval() {
+    if (hasInnerCorner()) {
+      setOvalLeft(getBorderBox().width() - (2 * getOuterCornerRadius() - getPostBorderWidth() / 2));
+      setOvalTop(getPreBorderWidth() / 2);
+      setOvalRight(getBorderBox().width() - getPostBorderWidth() / 2);
+      setOvalBottom(2 * getOuterCornerRadius() - getPreBorderWidth() / 2);
+    } else {
+      setOvalLeft(getBorderBox().width() - 1.5f * getOuterCornerRadius());
+      setOvalTop(getOuterCornerRadius() / 2);
+      setOvalRight(getBorderBox().width() - getOuterCornerRadius() / 2);
+      setOvalBottom(getOuterCornerRadius() * 1.5f);
+    }
+  }
+
+  @Override
+  protected void prepareRoundCorner() {
+    if (hasOuterCorner()) {
+      setRoundCornerStartX(getBorderBox().width() - getOuterCornerRadius());
+      setRoundCornerStartY(getPreBorderWidth() / 2);
+
+      setRoundCornerEndX(getBorderBox().width() - getPostBorderWidth() / 2);
+      setRoundCornerEndY(getOuterCornerRadius());
+    } else {
+      final float x = getBorderBox().width() - getPostBorderWidth() / 2;
+      final float y = getPreBorderWidth() / 2;
+
+      setRoundCornerStartX(x);
+      setRoundCornerStartY(y);
+
+      setRoundCornerEndX(x);
+      setRoundCornerEndY(y);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGesture.java b/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGesture.java
new file mode 100644
index 0000000..4b76bea
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGesture.java
@@ -0,0 +1,663 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.gesture;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.weex.bridge.EventResult;
+import org.apache.weex.common.Constants;
+import org.apache.weex.dom.WXEvent;
+import org.apache.weex.ui.component.Scrollable;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.view.gesture.WXGestureType.GestureInfo;
+import org.apache.weex.ui.view.gesture.WXGestureType.HighLevelGesture;
+import org.apache.weex.ui.view.gesture.WXGestureType.LowLevelGesture;
+import org.apache.weex.utils.WXLogUtils;
+import org.apache.weex.utils.WXUtils;
+import org.apache.weex.utils.WXViewUtils;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.common.Constants.Event;
+
+public class WXGesture extends GestureDetector.SimpleOnGestureListener implements OnTouchListener {
+
+  private final static String TAG = "Gesture";
+  private static final int CUR_EVENT = -1;
+  public static final String START = "start";
+  public static final String MOVE = "move";
+  public static final String END = "end";
+  public static final String UNKNOWN = "unknown";
+  public static final String LEFT = "left";
+  public static final String RIGHT = "right";
+  public static final String UP = "up";
+  public static final String DOWN = "down";
+  private WXComponent component;
+  private GestureDetector mGestureDetector;
+  private Rect globalRect;
+  private Point globalOffset;
+  private Point globalEventOffset;
+  private PointF locEventOffset;
+  private PointF locLeftTop;
+  private long swipeDownTime = -1;
+  private long panDownTime = -1;
+  private WXGestureType mPendingPan = null;//event type to notify when action_up or action_cancel
+  private int mParentOrientation =-1;
+  private boolean mIsPreventMoveEvent = false;
+  private boolean mIsTouchEventConsumed = false; //Reset to false when first touch event, set to true when gesture event fired.
+
+  private boolean requestDisallowInterceptTouchEvent = false;
+
+  private boolean shouldBubbleResult = true;
+  private int     shouldBubbleInterval = 0; //every times try
+  private int     shouldBubbleCallRemainTimes = 0;
+
+  private final List<OnTouchListener> mTouchListeners = new LinkedList<>();
+
+  public WXGesture(WXComponent wxComponent, Context context) {
+    this.component = wxComponent;
+    globalRect = new Rect();
+    globalOffset = new Point();
+    globalEventOffset = new Point();
+    locEventOffset = new PointF();
+    locLeftTop = new PointF();
+    mGestureDetector = new GestureDetector(context, this, new GestureHandler());
+    Scrollable parentScrollable = wxComponent.getParentScroller();
+    if(parentScrollable != null) {
+      mParentOrientation = parentScrollable.getOrientation();
+    }
+    shouldBubbleResult =  WXUtils.getBoolean(wxComponent.getAttrs().get(Constants.Name.SHOULD_STOP_PROPAGATION_INIT_RESULT), true);
+    shouldBubbleInterval = WXUtils.getNumberInt(wxComponent.getAttrs().get(Constants.Name.SHOULD_STOP_PROPAGATION_INTERVAL), 0);
+  }
+
+  private boolean isParentScrollable() {
+    if(component == null) {
+      return true;
+    }
+    Scrollable parentScrollable = component.getParentScroller();
+    return parentScrollable == null || parentScrollable.isScrollable();
+  }
+
+  private boolean hasSameOrientationWithParent(){
+    return (mParentOrientation == Constants.Orientation.HORIZONTAL && component.containsGesture(
+        HighLevelGesture.HORIZONTALPAN))
+            || (mParentOrientation == Constants.Orientation.VERTICAL && component.containsGesture(HighLevelGesture.VERTICALPAN));
+  }
+
+  public void setPreventMoveEvent(boolean preventMoveEvent) {
+    mIsPreventMoveEvent = preventMoveEvent;
+  }
+
+  /**
+   *
+   * @return true if current touch event is already consumed by gesture.
+   * Reset to false when next first touch event, set to true when gesture event fired.
+   */
+  public boolean isTouchEventConsumedByAdvancedGesture(){
+    return mIsTouchEventConsumed;
+  }
+
+
+  /**
+   * stoppropagation
+   * */
+  public static boolean isStopPropagation(String type){
+    return  Constants.Event.STOP_PROPAGATION.equals(type) || Constants.Event.STOP_PROPAGATION_RAX.equals(type);
+  }
+
+  public static boolean hasStopPropagation(WXComponent component){
+    WXEvent event = component.getEvents();
+    if(event == null){
+      return false;
+    }
+    int size = event.size();
+    for (int i=0; i<size; i++) {
+      if(i >= event.size()){
+        break;
+      }
+      String type = event.get(i);
+      if(isStopPropagation(type)){
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * shouldBubbleEvent default true
+   * */
+  private boolean shouldBubbleTouchEvent(MotionEvent event){
+    if(hasStopPropagation(component)){
+      if(shouldBubbleInterval > 0 && shouldBubbleCallRemainTimes > 0){
+        shouldBubbleCallRemainTimes--;
+        return  shouldBubbleResult;
+      }
+      Map<String, Object> eventMap = createFireEventParam(event, CUR_EVENT, null);
+      eventMap.put("type", "touch");
+      if(event.getAction() == MotionEvent.ACTION_DOWN){
+        eventMap.put("action", START);
+      }else if(event.getAction() == MotionEvent.ACTION_CANCEL
+              ||  event.getAction() == MotionEvent.ACTION_UP){
+        eventMap.put("action", END);
+      }else{
+        eventMap.put("action", MOVE);
+      }
+
+      String name = Event.STOP_PROPAGATION;
+      if(!component.getEvents().contains(Event.STOP_PROPAGATION)){
+         name = Event.STOP_PROPAGATION_RAX;
+      }
+      EventResult result = component.fireEventWait(name, eventMap);
+      if(result.isSuccess() && result.getResult() != null){
+        boolean stopPropagation = WXUtils.getBoolean(result.getResult(), !shouldBubbleResult);
+        shouldBubbleResult = !stopPropagation;
+      }
+      shouldBubbleCallRemainTimes = shouldBubbleInterval;
+      return shouldBubbleResult;
+
+    }
+    return  true;
+  }
+
+  @SuppressWarnings("unused")
+  public void addOnTouchListener(OnTouchListener listener) {
+    if(listener != null) {
+      mTouchListeners.add(listener);
+    }
+  }
+
+  @SuppressWarnings("unused")
+  public boolean removeTouchListener(OnTouchListener listener) {
+    if(listener != null) {
+      return mTouchListeners.remove(listener);
+    }
+    return false;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouch(View v, MotionEvent event) {
+    if(requestDisallowInterceptTouchEvent){
+      requestDisallowInterceptTouchEvent = false;
+      return false;
+    }
+    try {
+      boolean result = mGestureDetector.onTouchEvent(event);
+
+      if(mTouchListeners != null && !mTouchListeners.isEmpty()) {
+        for(OnTouchListener listener : mTouchListeners) {
+          result |= listener.onTouch(v, event);
+        }
+      }
+
+      switch (event.getActionMasked()) {
+        case MotionEvent.ACTION_POINTER_DOWN:
+        case MotionEvent.ACTION_DOWN:
+          mIsTouchEventConsumed = false;
+          /**
+           * If component has same scroll orientation with it's parent and it's parent not scrollable
+           * , we should disallow parent in DOWN.
+           */
+          if(hasSameOrientationWithParent() && !isParentScrollable()){
+            ViewParent p;
+            if ((p = component.getRealView().getParent()) != null) {
+              p.requestDisallowInterceptTouchEvent(true);
+            }
+          }
+          result |= handleMotionEvent(LowLevelGesture.ACTION_DOWN, event);
+          break;
+        case MotionEvent.ACTION_MOVE:
+          result |= handleMotionEvent(LowLevelGesture.ACTION_MOVE, event);
+          break;
+        case MotionEvent.ACTION_UP:
+        case MotionEvent.ACTION_POINTER_UP:
+          finishDisallowInterceptTouchEvent(v);
+          result |= handleMotionEvent(LowLevelGesture.ACTION_UP, event);
+          result |= handlePanMotionEvent(event);
+          break;
+        case MotionEvent.ACTION_CANCEL:
+          finishDisallowInterceptTouchEvent(v);
+          result |= handleMotionEvent(LowLevelGesture.ACTION_CANCEL, event);
+          result |= handlePanMotionEvent(event);
+          break;
+      }
+      if(hasStopPropagation(component)){
+        ViewGroup parent = (ViewGroup) v.getParent();
+        boolean requestDisallowInterceptTouchEvent = false;
+        if(parent != null){
+          if(!shouldBubbleTouchEvent(event)){
+            requestDisallowInterceptTouchEvent = true;
+          }
+          parent.requestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
+        }
+        if(component.getParent() != null){
+          component.getParent().requestDisallowInterceptTouchEvent(requestDisallowInterceptTouchEvent);
+        }
+        if(mIsTouchEventConsumed && WXUtils.getBoolean(component.getAttrs().get("cancelTouchOnConsume"), false)){//when touch event consumed by one gesture, other component should not consumed
+          event.setAction(MotionEvent.ACTION_CANCEL);
+        }
+      }
+      return result;
+    } catch (Exception e) {
+      WXLogUtils.e("Gesture RunTime Error ", e);
+      return false;
+    }
+  }
+
+  private String getPanEventAction(MotionEvent event) {
+    switch (event.getAction()) {
+      case MotionEvent.ACTION_DOWN:
+        return START;
+      case MotionEvent.ACTION_MOVE:
+        return MOVE;
+      case MotionEvent.ACTION_UP:
+        return END;
+      case MotionEvent.ACTION_CANCEL:
+        return END;
+      default:
+        return UNKNOWN;
+    }
+  }
+
+  private void finishDisallowInterceptTouchEvent(View v){
+    if(v.getParent() != null){
+      v.getParent().requestDisallowInterceptTouchEvent(false);
+    }
+  }
+
+  private boolean handlePanMotionEvent(MotionEvent motionEvent) {
+    if (mPendingPan == null) {
+      return false;
+    }
+    String state = null;
+    if (mPendingPan == HighLevelGesture.HORIZONTALPAN || mPendingPan == HighLevelGesture.VERTICALPAN) {
+      state = getPanEventAction(motionEvent);
+
+    }
+
+    if (component.containsGesture(mPendingPan)) {
+      if(mIsPreventMoveEvent && MOVE.equals(state)){
+        return true;
+      }
+      List<Map<String, Object>> list = createMultipleFireEventParam(motionEvent, state);
+      for (Map<String, Object> map : list) {
+        component.fireEvent(mPendingPan.toString(), map);
+      }
+      //action is finish, clean pending pan
+      if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
+        mPendingPan = null;
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   *
+   * @param WXGestureType possible low-level gesture, defined in {@link Event}
+   * @param motionEvent motionEvent, which contains all pointers event in a period of time
+   * @return true if this event is handled, otherwise false.
+   */
+  private boolean handleMotionEvent(WXGestureType WXGestureType, MotionEvent motionEvent) {
+    if (component.containsGesture(WXGestureType)) {
+      List<Map<String, Object>> list = createMultipleFireEventParam(motionEvent, null);
+      for (Map<String, Object> map : list) {
+        component.fireEvent(WXGestureType.toString(), map);
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Create a list of event for {@link WXSDKInstance#fireEvent(String, String, Map, Map)}.
+   * As there is a batch mechanism in MotionEvent, so this method returns a list.
+   * @param motionEvent motionEvent, which contains all pointers event in a period of time
+   * @return List of Map, which contains touch object.
+   */
+  private List<Map<String, Object>> createMultipleFireEventParam(MotionEvent motionEvent,String state) {
+    List<Map<String, Object>> list = new ArrayList<>(motionEvent.getHistorySize() + 1);
+    //list.addAll(getHistoricalEvents(motionEvent));
+    list.add(createFireEventParam(motionEvent, CUR_EVENT, state));
+    return list;
+  }
+
+  /**
+   * Get historical event. This is only applied to {@link MotionEvent#ACTION_MOVE}.
+   * For other types of motionEvent, historical event is meaningless.
+   * @param motionEvent motionEvent, which contains all pointers event in a period of time
+   * @return If motionEvent.getActionMasked()!=MotionEvent.ACTION_MOVE,
+   * this method will return an empty list.
+   * Otherwise this method will return the historical motionEvent, which may also be empty.
+   */
+  private List<Map<String, Object>> getHistoricalEvents(MotionEvent motionEvent) {
+    List<Map<String, Object>> list = new ArrayList<>(motionEvent.getHistorySize());
+    if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
+      Map<String, Object> param;
+      for (int i = 0; i < motionEvent.getHistorySize(); i++) {
+        param = createFireEventParam(motionEvent, i,null);
+        list.add(param);
+      }
+    }
+    return list;
+  }
+
+  /**
+   * Create a map represented touch event at a certain moment.
+   * @param motionEvent motionEvent, which contains all pointers event in a period of time
+   * @param pos index used to retrieve a certain moment in a period of time.
+   * @return touchEvent
+   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent">touchEvent</a>
+   */
+  private Map<String, Object> createFireEventParam(MotionEvent motionEvent, int pos, String state) {
+    JSONArray jsonArray = new JSONArray(motionEvent.getPointerCount());
+    if (motionEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
+      for (int i = 0; i < motionEvent.getPointerCount(); i++) {
+        jsonArray.add(createJSONObject(motionEvent, pos, i));
+      }
+    } else if (isPointerNumChanged(motionEvent)) {
+      int pointerIndex = motionEvent.getActionIndex();
+      jsonArray.add(createJSONObject(motionEvent, CUR_EVENT, pointerIndex));
+    }
+    Map<String, Object> map = new HashMap<>();
+    map.put(GestureInfo.HISTORICAL_XY, jsonArray);
+    if (state != null) {
+      map.put(GestureInfo.STATE, state);
+    }
+    return map;
+  }
+
+  /**
+   * Tell whether the number of motion event's pointer changed.
+   * @param event the current motion event
+   * @return true for number of motion event's pointer changed, otherwise false.
+   */
+  private boolean isPointerNumChanged(MotionEvent event) {
+    return event.getActionMasked() == MotionEvent.ACTION_DOWN ||
+            event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN ||
+            event.getActionMasked() == MotionEvent.ACTION_UP ||
+            event.getActionMasked() == MotionEvent.ACTION_POINTER_UP ||
+            event.getActionMasked() == MotionEvent.ACTION_CANCEL;
+  }
+
+  /**
+   * Tell whether component contains pan gesture
+   * @return true for contains pan gesture, otherwise false.
+   */
+  private boolean containsSimplePan() {
+    return component.containsGesture(HighLevelGesture.PAN_START) ||
+            component.containsGesture(HighLevelGesture.PAN_MOVE) ||
+            component.containsGesture(HighLevelGesture.PAN_END);
+  }
+
+  /**
+   * Create a touchObject for a pointer at a certain moment.
+   * @param motionEvent motionEvent, which contains all pointers event in a period of time
+   * @param pos index used to retrieve a certain moment in a period of time.
+   * @param pointerIndex pointerIndex
+   * @return JSONObject represent a touch event
+   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch">touch</a>
+   */
+  private JSONObject createJSONObject(MotionEvent motionEvent, int pos, int pointerIndex) {
+    PointF screenXY, pageXY;
+    if (pos == CUR_EVENT) {
+      pageXY = getEventLocInPageCoordinate(motionEvent, pointerIndex);
+      screenXY = getEventLocInScreenCoordinate(motionEvent, pointerIndex);
+    } else {
+      pageXY = getEventLocInPageCoordinate(motionEvent, pointerIndex, pos);
+      screenXY = getEventLocInScreenCoordinate(motionEvent, pointerIndex, pos);
+    }
+    JSONObject map = createJSONObject(screenXY, pageXY, (float) motionEvent.getPointerId(pointerIndex));
+    float force = motionEvent.getPressure();
+    if(force > 0 && force < 1) {
+      map.put("force", motionEvent.getPressure());
+    }
+    return map;
+  }
+
+  /**
+   * Create a touchObject for a pointer at a certain moment.
+   * @param screenXY the point of event happened in screen coordinate
+   * @param pageXY the point of event happened in page coorindate
+   * @param pointerId pointerIndex pointerIndex
+   * @return JSONObject represent a touch event
+   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch">touch</a>
+   */
+  @NonNull
+  private JSONObject createJSONObject(PointF screenXY, PointF pageXY, float pointerId) {
+    JSONObject jsonObject = new JSONObject();
+    jsonObject.put(GestureInfo.PAGE_X, pageXY.x);
+    jsonObject.put(GestureInfo.PAGE_Y, pageXY.y);
+    jsonObject.put(GestureInfo.SCREEN_X, screenXY.x);
+    jsonObject.put(GestureInfo.SCREEN_Y, screenXY.y);
+    jsonObject.put(GestureInfo.POINTER_ID, pointerId);
+    return jsonObject;
+  }
+
+  /**
+   * @see {@link #getEventLocInScreenCoordinate(MotionEvent, int, int)}
+   */
+  private PointF getEventLocInScreenCoordinate(MotionEvent motionEvent, int pointerIndex) {
+    return getEventLocInScreenCoordinate(motionEvent, pointerIndex, CUR_EVENT);
+  }
+
+  /**
+   * Get event location in Screen's coordinate, e.g. root(global) coordinate.
+   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/screenX">screenX</a>
+   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/screenY">screenY</a>
+   * @param motionEvent the original motionEvent
+   * @param pointerIndex pointerIndex
+   * @param position if motionEvent.getHistoricalSize()!=0, the is the index of historical event,
+   *                 otherwise this is {@link #CUR_EVENT} which indicates historicalSize is zero
+   * @return the eventLocation in screen's coordinate
+   */
+  private PointF getEventLocInScreenCoordinate(MotionEvent motionEvent, int pointerIndex, int position) {
+    float eventX, eventY;
+    if (position == CUR_EVENT) {
+      eventX = motionEvent.getX(pointerIndex);
+      eventY = motionEvent.getY(pointerIndex);
+    } else {
+      eventX = motionEvent.getHistoricalX(pointerIndex, position);
+      eventY = motionEvent.getHistoricalY(pointerIndex, position);
+    }
+    return getEventLocInScreenCoordinate(eventX, eventY);
+  }
+
+  /**
+   * Get event location in Screen's coordinate, e.g. root(global) coordinate.
+   * @param eventX {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
+   * @param eventY {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
+   * @return the eventLocation in screen's coordinate
+   * @see {@link #getEventLocInScreenCoordinate(MotionEvent, int, int)}
+   */
+  @NonNull
+  private PointF getEventLocInScreenCoordinate(float eventX, float eventY) {
+    globalRect.set(0, 0, 0, 0);
+    globalOffset.set(0, 0);
+    globalEventOffset.set((int) eventX, (int) eventY);
+    component.getRealView().getGlobalVisibleRect(globalRect, globalOffset);
+    globalEventOffset.offset(globalOffset.x, globalOffset.y);
+    return new PointF(WXViewUtils.getWebPxByWidth(globalEventOffset.x,component.getInstance().getInstanceViewPortWidth()),
+            WXViewUtils.getWebPxByWidth(globalEventOffset.y,component.getInstance().getInstanceViewPortWidth()));
+  }
+
+  /**
+   * @see {@link #getEventLocInPageCoordinate(MotionEvent, int, int)}
+   */
+  private PointF getEventLocInPageCoordinate(MotionEvent motionEvent, int pointerIndex) {
+    return getEventLocInPageCoordinate(motionEvent, pointerIndex, CUR_EVENT);
+  }
+
+  /**
+   * Get event's location in Document's (Page) coordinate.
+   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/pageX">pageX</a>
+   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch/pageY">pageY</a>
+   * @param motionEvent the original motionEvent
+   * @param pointerIndex pointerIndex
+   * @param position if motionEvent.getHistoricalSize()!=0, the is the index of historical event,
+   *                 otherwise this is {@link #CUR_EVENT} which indicates historicalSize is zero
+   * @return the event location in page's coordinate.
+   */
+  private PointF getEventLocInPageCoordinate(MotionEvent motionEvent, int pointerIndex, int position) {
+    float eventX, eventY;
+    if (position == CUR_EVENT) {
+      eventX = motionEvent.getX(pointerIndex);
+      eventY = motionEvent.getY(pointerIndex);
+    } else {
+      eventX = motionEvent.getHistoricalX(pointerIndex, position);
+      eventY = motionEvent.getHistoricalY(pointerIndex, position);
+    }
+    return getEventLocInPageCoordinate(eventX, eventY);
+  }
+
+  /**
+   * Get event's location in Document's (Page) coordinate.
+   * @param eventX {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
+   * @param eventY {@link MotionEvent#getX()} or {@link MotionEvent#getHistoricalX(int, int)}
+   * @return the event location in page's coordinate.
+   * @see {@link #getEventLocInPageCoordinate(MotionEvent, int, int)}
+   */
+  @NonNull
+  private PointF getEventLocInPageCoordinate(float eventX, float eventY) {
+    locEventOffset.set(eventX, eventY);
+    locLeftTop.set(0, 0);
+    component.computeVisiblePointInViewCoordinate(locLeftTop);
+    locEventOffset.offset(locLeftTop.x, locLeftTop.y);
+    return new PointF(WXViewUtils.getWebPxByWidth(locEventOffset.x,component.getInstance().getInstanceViewPortWidth()),
+            WXViewUtils.getWebPxByWidth(locEventOffset.y,component.getInstance().getInstanceViewPortWidth()));
+  }
+
+  private static class GestureHandler extends android.os.Handler {
+
+    public GestureHandler() {
+      super(Looper.getMainLooper());
+    }
+  }
+
+
+  /***************** OnGestureListener ****************/
+
+  @Override
+  public void onLongPress(MotionEvent e) {
+    if (component.containsGesture(HighLevelGesture.LONG_PRESS)) {
+      List<Map<String, Object>> list = createMultipleFireEventParam(e,null);
+      component.getInstance().fireEvent(
+              component.getRef(),
+              HighLevelGesture.LONG_PRESS.toString(),
+              list.get(list.size() - 1));
+      mIsTouchEventConsumed = true;
+    }
+  }
+
+  /**
+   * Gesture priority:horizontalPan & verticalPan > pan > swipe
+   */
+  @Override
+  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+    boolean result = false;
+    if (e1 == null || e2 == null) {
+      return false;
+    }
+    float dx = Math.abs(e2.getX() - e1.getX());
+    float dy = Math.abs(e2.getY() - e1.getY());
+    WXGestureType possiblePan;
+    if (dx > dy) {
+      possiblePan = HighLevelGesture.HORIZONTALPAN;
+    } else {
+      possiblePan = HighLevelGesture.VERTICALPAN;
+    }
+    if (mPendingPan == HighLevelGesture.HORIZONTALPAN || mPendingPan == HighLevelGesture.VERTICALPAN) {
+      //already during directional-pan
+      result = handlePanMotionEvent(e2);
+    } else if (component.containsGesture(possiblePan)) {
+      ViewParent p;
+      if ((p = component.getRealView().getParent()) != null) {
+        p.requestDisallowInterceptTouchEvent(true);
+      }
+      if (mPendingPan != null) {
+        handleMotionEvent(mPendingPan, e2);//finish pan if exist
+      }
+      mPendingPan = possiblePan;
+      component.fireEvent(possiblePan.toString(), createFireEventParam(e2, CUR_EVENT, START));
+
+      result = true;
+    } else if (containsSimplePan()) {
+      if (panDownTime != e1.getEventTime()) {
+        panDownTime = e1.getEventTime();
+        mPendingPan = HighLevelGesture.PAN_END;
+        component.fireEvent(HighLevelGesture.PAN_START.toString(),
+                createFireEventParam(e1, CUR_EVENT, null));
+      } else {
+        component.fireEvent(HighLevelGesture.PAN_MOVE.toString(),
+                createFireEventParam(e2, CUR_EVENT, null));
+      }
+      result = true;
+    } else if (component.containsGesture(HighLevelGesture.SWIPE)) {
+      if (swipeDownTime != e1.getEventTime()) {
+        swipeDownTime = e1.getEventTime();
+        List<Map<String, Object>> list = createMultipleFireEventParam(e2, null);
+        Map<String, Object> param = list.get(list.size() - 1);
+        if (Math.abs(distanceX) > Math.abs(distanceY)) {
+          param.put(GestureInfo.DIRECTION, distanceX > 0 ? LEFT : RIGHT);
+        } else {
+          param.put(GestureInfo.DIRECTION, distanceY > 0 ? UP : DOWN);
+        }
+        component.getInstance().fireEvent(component.getRef(),
+                HighLevelGesture.SWIPE.toString(), param);
+        result = true;
+      }
+    }
+    mIsTouchEventConsumed = mIsTouchEventConsumed || result;
+    return result;
+  }
+
+  @Override
+  public boolean onDown(MotionEvent e) {
+    return true;
+  }
+
+  public boolean isRequestDisallowInterceptTouchEvent() {
+    return requestDisallowInterceptTouchEvent;
+  }
+
+  public void setRequestDisallowInterceptTouchEvent(boolean requestDisallowInterceptTouchEvent) {
+    this.requestDisallowInterceptTouchEvent = requestDisallowInterceptTouchEvent;
+  }
+
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGestureObservable.java b/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGestureObservable.java
new file mode 100644
index 0000000..9cab499
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGestureObservable.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.gesture;
+
+import android.support.annotation.Nullable;
+import android.view.MotionEvent;
+import android.view.View;
+
+import org.apache.weex.ui.view.WXFrameLayout;
+
+/**
+ * Views that want to receive Gesture Event must implement this interface. Besides,
+ * those view must override their {@link android.view.View#onTouchEvent(MotionEvent)}
+ * and add method invocation to {@link WXGesture#onTouch(View, MotionEvent)}.
+ * Refer to {@link WXFrameLayout#onTouchEvent(MotionEvent)} for more info.
+ *
+ */
+public interface WXGestureObservable {
+
+  /**
+   * Register a {@link WXGesture} for corresponding view.
+   * @param wxGesture The Gesture to register, null for unregister.
+   */
+  void registerGestureListener(@Nullable WXGesture wxGesture);
+
+  /**
+   * Get gesture listener for corresponding view.
+   *
+   * @return the gesture listener has register before
+   *
+   * */
+  WXGesture getGestureListener();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGestureType.java b/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGestureType.java
new file mode 100644
index 0000000..f6620fe
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/gesture/WXGestureType.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.gesture;
+
+public interface WXGestureType {
+
+  enum LowLevelGesture implements WXGestureType {
+    ACTION_DOWN("touchstart"),
+    ACTION_MOVE("touchmove"),
+    ACTION_UP("touchend"),
+    ACTION_CANCEL("touchcancel");
+    private String description;
+
+    LowLevelGesture(String description) {
+      this.description = description;
+    }
+
+    @Override
+    public String toString() {
+      return description;
+    }
+  }
+
+  enum HighLevelGesture implements WXGestureType {
+    SWIPE("swipe"),
+    LONG_PRESS("longpress"),
+    PAN_START("panstart"),
+    PAN_MOVE("panmove"),
+    PAN_END("panend"),
+    HORIZONTALPAN("horizontalpan"),
+    VERTICALPAN("verticalpan");
+    private String description;
+
+    HighLevelGesture(String description) {
+      this.description = description;
+    }
+
+    @Override
+    public String toString() {
+      return description;
+    }
+  }
+
+  class GestureInfo {
+
+    public static final String HISTORICAL_XY = "changedTouches";
+    public static final String PAGE_X = "pageX";
+    public static final String PAGE_Y = "pageY";
+    public static final String SCREEN_X = "screenX";
+    public static final String SCREEN_Y = "screenY";
+    public static final String POINTER_ID = "identifier";
+    public static final String DIRECTION = "direction";
+    public static final String STATE = "state";
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/ExtendedLinearLayoutManager.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/ExtendedLinearLayoutManager.java
new file mode 100644
index 0000000..c4dd32a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/ExtendedLinearLayoutManager.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.LinearSmoothScroller;
+import android.support.v7.widget.RecyclerView;
+
+/**
+ * Created by moxun on 17/2/16.
+ */
+
+public class ExtendedLinearLayoutManager extends LinearLayoutManager{
+
+    private RecyclerView.SmoothScroller smoothScroller;
+
+
+    private OnSmoothScrollEndListener onScrollEndListener;
+
+    public ExtendedLinearLayoutManager(Context context) {
+        super(context, VERTICAL, false);
+    }
+
+    public ExtendedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
+        super(context, orientation, reverseLayout);
+    }
+
+    @Override
+    public boolean supportsPredictiveItemAnimations() {
+        return false;
+    }
+
+    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        try {
+            super.onLayoutChildren(recycler, state);
+        } catch (IndexOutOfBoundsException e) {
+            e.printStackTrace();
+
+        }
+    }
+
+    @Override
+    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
+        try {
+            return super.scrollVerticallyBy(dy, recycler, state);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+
+    @Override
+    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
+                                       int position) {
+        if (smoothScroller == null) {
+            smoothScroller = new ExtendedLinearLayoutManager.TopSnappedSmoothScroller(recyclerView.getContext());
+        }
+        smoothScroller.setTargetPosition(position);
+        startSmoothScroll(smoothScroller);
+    }
+
+    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
+        public TopSnappedSmoothScroller(Context context) {
+            super(context);
+
+        }
+
+        @Override
+        public PointF computeScrollVectorForPosition(int targetPosition) {
+            return ExtendedLinearLayoutManager.this
+                    .computeScrollVectorForPosition(targetPosition);
+        }
+
+        @Override
+        protected int getVerticalSnapPreference() {
+            return SNAP_TO_START;
+        }
+
+        @Override
+        protected void onStop() {
+            super.onStop();
+            if(onScrollEndListener != null){
+                onScrollEndListener.onStop();
+                onScrollEndListener = null;
+            }
+        }
+    }
+
+    public void setOnScrollEndListener(OnSmoothScrollEndListener onScrollEndListener) {
+        this.onScrollEndListener = onScrollEndListener;
+    }
+
+    public interface OnSmoothScrollEndListener {
+        void  onStop();
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/ExtendedStaggeredGridLayoutManager.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/ExtendedStaggeredGridLayoutManager.java
new file mode 100644
index 0000000..a49d110
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/ExtendedStaggeredGridLayoutManager.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.utils.WXLogUtils;
+
+/**
+ * Created by zhengshihan on 2017/5/5.
+ */
+
+public class ExtendedStaggeredGridLayoutManager extends StaggeredGridLayoutManager{
+
+  public ExtendedStaggeredGridLayoutManager(int spanCount, int orientation) {
+    super(spanCount, orientation);
+  }
+
+  @Override
+  public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
+    if(positionStart ==-1){
+      WXLogUtils.e("ExtendedStaggeredGridLayoutManager: onItemsRemoved  Error Invalid Index : positionStart :"+positionStart +"  itemCount:"+ itemCount);
+      return ;
+    }else {
+      if(WXEnvironment.isApkDebugable()){
+        WXLogUtils.e("ExtendedStaggeredGridLayoutManager: onItemsRemoved  positionStart :"+positionStart+"  itemCount:"+ itemCount);
+      }
+    }
+    super.onItemsRemoved(recyclerView, positionStart, itemCount);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/WXRecyclerView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/WXRecyclerView.java
new file mode 100644
index 0000000..0bc6b96
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/WXRecyclerView.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.OrientationHelper;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.MotionEvent;
+
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXThread;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+
+public class WXRecyclerView extends RecyclerView implements WXGestureObservable {
+
+  public static final int TYPE_LINEAR_LAYOUT = 1;
+  public static final int TYPE_GRID_LAYOUT = 2;
+  public static final int TYPE_STAGGERED_GRID_LAYOUT = 3;
+  private WXGesture mGesture;
+  private boolean scrollable = true;
+  private boolean hasTouch = false;
+
+
+  public WXRecyclerView(Context context) {
+    super(context);
+  }
+
+  public boolean isScrollable() {
+    return scrollable;
+  }
+
+  public void setScrollable(boolean scrollable) {
+    this.scrollable = scrollable;
+  }
+
+  public void initView(Context context, int type,int orientation) {
+    initView(context,type, Constants.Value.COLUMN_COUNT_NORMAL,Constants.Value.COLUMN_GAP_NORMAL,orientation);
+  }
+
+
+  /**
+   *
+   * @param context
+   * @param type
+   * @param orientation should be {@link OrientationHelper#HORIZONTAL} or {@link OrientationHelper#VERTICAL}
+   */
+  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+  public void initView(Context context, int type, int columnCount, float columnGap, int orientation) {
+    if (type == TYPE_GRID_LAYOUT) {
+      setLayoutManager(new GridLayoutManager(context, columnCount,orientation,false));
+    } else if (type == TYPE_STAGGERED_GRID_LAYOUT) {
+      setLayoutManager(new ExtendedStaggeredGridLayoutManager(columnCount, orientation));
+    } else if (type == TYPE_LINEAR_LAYOUT) {
+      setLayoutManager(new ExtendedLinearLayoutManager(context,orientation,false));
+    }
+  }
+
+  @Override
+  public void registerGestureListener(@Nullable WXGesture wxGesture) {
+    mGesture = wxGesture;
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return mGesture;
+  }
+
+  @SuppressLint("ClickableViewAccessibility")
+  @Override
+  public boolean onTouchEvent(MotionEvent event) {
+    if(!scrollable) {
+      return true;
+    }
+    return super.onTouchEvent(event);
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(MotionEvent event) {
+    hasTouch = true;
+    boolean result = super.dispatchTouchEvent(event);
+    if (mGesture != null) {
+      result |= mGesture.onTouch(this, event);
+    }
+    return result;
+  }
+
+  public void scrollTo(boolean smooth, int position, final  int offset, final int orientation){
+    if (!smooth) {
+      RecyclerView.LayoutManager layoutManager = getLayoutManager();
+      if (layoutManager instanceof LinearLayoutManager) {
+        //GridLayoutManager is also instance of LinearLayoutManager
+        ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, -offset);
+      } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+        ((StaggeredGridLayoutManager) layoutManager).scrollToPositionWithOffset(position, -offset);
+      }
+      //Any else?
+    } else {
+      smoothScrollToPosition(position);
+      if (offset != 0) {
+        setOnSmoothScrollEndListener(new ExtendedLinearLayoutManager.OnSmoothScrollEndListener() {
+          @Override
+          public void onStop() {
+            post(WXThread.secure(new Runnable() {
+              @Override
+              public void run() {
+                if (orientation == Constants.Orientation.VERTICAL) {
+                  smoothScrollBy(0, offset);
+                } else {
+                  smoothScrollBy(offset, 0);
+                }
+              }
+            }));
+          }
+        });
+      }
+    }
+  }
+
+  public void setOnSmoothScrollEndListener(final ExtendedLinearLayoutManager.OnSmoothScrollEndListener onSmoothScrollEndListener){
+    addOnScrollListener(new RecyclerView.OnScrollListener() {
+      @Override
+      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+          recyclerView.removeOnScrollListener(this);
+          if(onSmoothScrollEndListener != null){
+            onSmoothScrollEndListener.onStop();
+          }
+        }
+      }
+    });
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/IOnLoadMoreListener.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/IOnLoadMoreListener.java
new file mode 100644
index 0000000..79632b2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/IOnLoadMoreListener.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview.adapter;
+
+
+public interface IOnLoadMoreListener {
+
+  void onLoadMore(int offScreenY);
+  void notifyAppearStateChange(int firstVisible, int lastVisible, int directionX, int directionY);
+  void onBeforeScroll(int dx, int dy);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/IRecyclerAdapterListener.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/IRecyclerAdapterListener.java
new file mode 100644
index 0000000..934cd5d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/IRecyclerAdapterListener.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview.adapter;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.ViewGroup;
+
+/**
+ * Listener for recyclerView event
+ */
+public interface IRecyclerAdapterListener<T extends RecyclerView.ViewHolder> {
+
+  void onViewRecycled(T holder);
+
+  void onBindViewHolder(T holder, int position);
+
+  T onCreateViewHolder(ViewGroup parent, int viewType);
+
+  int getItemViewType(int position);
+
+  int getItemCount();
+
+  boolean onFailedToRecycleView(T holder);
+
+  long getItemId(int position);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/ListBaseViewHolder.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/ListBaseViewHolder.java
new file mode 100644
index 0000000..ce959ae
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/ListBaseViewHolder.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview.adapter;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.component.WXHeader;
+
+import java.lang.ref.WeakReference;
+
+
+/**
+ * There are bi-directional association between ViewHolder and View.
+ * This is accomplished by weak-reference and final field from ViewHolder to View.
+ * From View to ViewHolder, this is done by set {@link android.view.ViewGroup.LayoutParams} to View.
+ */
+public class ListBaseViewHolder extends RecyclerView.ViewHolder {
+  private int mViewType;
+  private boolean isRecycled;
+  private WeakReference<WXComponent> mComponent;
+
+  public ListBaseViewHolder(WXComponent component, int viewType) {
+    super(component.getHostView());
+    mViewType = viewType;
+    mComponent = new WeakReference(component);
+    // This tag is used to determine whether bind / rebind data is needed.
+    // It should be false When component can not be recycled Which means
+    // no need to bind / rebind data.
+    isRecycled = component.canRecycled();
+  }
+
+  public ListBaseViewHolder(WXComponent component, int viewType, boolean forceBindData) {
+    this(component, viewType);
+    isRecycled = isRecycled || forceBindData;
+  }
+
+  public ListBaseViewHolder(View view, int viewType) {
+    super(view);
+    mViewType = viewType;
+  }
+
+  public boolean isRecycled() {
+    return isRecycled;
+  }
+
+  public void recycled() {
+    if (mComponent != null && mComponent.get() != null) {
+      mComponent.get().recycled();
+      isRecycled = true;
+
+    }
+  }
+
+  public void bindData(WXComponent component) {
+    if (mComponent != null && mComponent.get() != null) {
+      mComponent.get().bindData(component);
+      isRecycled = false;
+    }
+  }
+    
+  public boolean isFullSpan() {
+    return mComponent != null && mComponent.get() instanceof WXHeader;
+  }
+
+  public boolean canRecycled() {
+    if (mComponent != null && mComponent.get() != null) {
+      return mComponent.get().canRecycled();
+    }
+    return true;
+  }
+
+  public View getView() {
+    return itemView;
+  }
+
+  public int getViewType() {
+    return mViewType;
+  }
+
+  public void setComponentUsing(boolean using) {
+    if (mComponent != null && mComponent.get() != null)
+      mComponent.get().setUsing(using);
+  }
+
+  public WXComponent getComponent() {
+    return mComponent != null ? mComponent.get() : null;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/RecyclerViewBaseAdapter.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/RecyclerViewBaseAdapter.java
new file mode 100644
index 0000000..38ce0a2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/RecyclerViewBaseAdapter.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview.adapter;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.ViewGroup;
+
+
+/**
+ * Adapter for recyclerView
+ */
+public class RecyclerViewBaseAdapter<T extends ListBaseViewHolder> extends RecyclerView.Adapter<T> {
+
+  private IRecyclerAdapterListener iRecyclerAdapterListener;
+
+  public RecyclerViewBaseAdapter(IRecyclerAdapterListener Listener) {
+    this.iRecyclerAdapterListener = Listener;
+  }
+
+  @Override
+  public T onCreateViewHolder(ViewGroup parent, int viewType) {
+    if (iRecyclerAdapterListener != null) {
+      return (T) iRecyclerAdapterListener.onCreateViewHolder(parent, viewType);
+    }
+
+    return null;
+  }
+
+  @Override
+  public void onViewAttachedToWindow(T holder) {
+    super.onViewAttachedToWindow(holder);
+    if( holder !=null && holder.isFullSpan()){
+      ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+      if(lp != null
+              && lp instanceof StaggeredGridLayoutManager.LayoutParams
+              ) {
+        StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
+        p.setFullSpan(true);
+      }
+    }
+  }
+
+  @Override
+  public void onViewDetachedFromWindow(T holder) {
+    super.onViewDetachedFromWindow(holder);
+    if (holder != null)
+      holder.setComponentUsing(false);
+  }
+
+  @Override
+  public void onBindViewHolder(T viewHolder, int i) {
+    if (iRecyclerAdapterListener != null) {
+      iRecyclerAdapterListener.onBindViewHolder(viewHolder, i);
+    }
+  }
+
+  @Override
+  public int getItemViewType(int position) {
+    if (iRecyclerAdapterListener != null) {
+      return iRecyclerAdapterListener.getItemViewType(position);
+    }
+    return position;
+  }
+
+  @Override
+  public long getItemId(int position) {
+    return iRecyclerAdapterListener.getItemId(position);
+  }
+
+  @Override
+  public int getItemCount() {
+    if (iRecyclerAdapterListener != null) {
+      return iRecyclerAdapterListener.getItemCount();
+    }
+    return 0;
+  }
+
+  @Override
+  public void onViewRecycled(T holder) {
+    if (iRecyclerAdapterListener != null) {
+      iRecyclerAdapterListener.onViewRecycled(holder);
+    }
+    super.onViewRecycled(holder);
+  }
+
+  @Override
+  public boolean onFailedToRecycleView(T holder) {
+    if (iRecyclerAdapterListener != null) {
+      return iRecyclerAdapterListener.onFailedToRecycleView(holder);
+    }
+    return super.onFailedToRecycleView(holder);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/TransformItemDecoration.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/TransformItemDecoration.java
new file mode 100644
index 0000000..2dae5c3
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/TransformItemDecoration.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview.adapter;
+
+import android.graphics.Canvas;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+public class TransformItemDecoration extends RecyclerView.ItemDecoration{
+  boolean mIsVertical = true;
+  float mAlpha = -1f;
+  int mXTranslate = 0;
+  int mYTranslate = 0;
+  int mRotation = 0;
+  float mScaleX = 0;
+  float mScaleY  = 0;
+
+  public TransformItemDecoration(boolean isVertical,float alpha,int translateX,int translateY,int rotation,float scaleX,float scaleY){
+    this.mIsVertical = isVertical;
+    this.mAlpha = alpha;
+    this.mXTranslate = translateX;
+    this.mYTranslate = translateY;
+    this.mRotation = rotation;
+    this.mScaleX = scaleX;
+    this.mScaleY = scaleY;
+  }
+
+
+  @Override
+  public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+    super.onDrawOver(c, parent, state);
+    int width = parent.getWidth();
+    int height = parent.getHeight();
+    for (int i = 0,count=parent.getChildCount(); i < count; i++) {
+      updateItem(parent.getChildAt(i),width,height);
+    }
+  }
+
+  private void updateItem(View child, int width, int height) {
+    int size,childCenter,containerSize;
+    if (mIsVertical) {
+      containerSize = height;
+      size = child.getHeight();
+      childCenter = child.getTop() + size / 2;
+    } else {
+      containerSize = width;
+      size = child.getWidth();
+      childCenter = child.getLeft() + size / 2;
+    }
+
+    final int actionDistance = (containerSize + size) / 2;
+    final float effectsAmount = Math.min(1.0f, Math.max(-1.0f, (1.0f / actionDistance) * (childCenter - containerSize/2)));
+
+
+    if(mAlpha>0){
+      child.setAlpha(1-mAlpha*Math.abs(effectsAmount));
+    }
+
+    if(mScaleX>0||mScaleY>0){
+      child.setScaleX(1-mScaleX*Math.abs(effectsAmount));
+      child.setScaleY(1-mScaleY*Math.abs(effectsAmount));
+    }
+
+    if(mRotation!=0){
+      child.setRotation(mRotation * effectsAmount);
+    }
+
+    if(mXTranslate!=0){
+      child.setTranslationX(mXTranslate * Math.abs( effectsAmount));
+    }
+
+    if(mYTranslate!=0){
+      child.setTranslationY(mYTranslate * Math.abs( effectsAmount));
+    }
+
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/WXRecyclerViewOnScrollListener.java b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/WXRecyclerViewOnScrollListener.java
new file mode 100644
index 0000000..fd14e1b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/listview/adapter/WXRecyclerViewOnScrollListener.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.listview.adapter;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.ref.WeakReference;
+
+
+/**
+ * Listener for scroll event of recyclerView
+ */
+public class WXRecyclerViewOnScrollListener extends RecyclerView.OnScrollListener {
+
+  /**
+   * type of layoutManager
+   */
+  protected LAYOUT_MANAGER_TYPE layoutManagerType;
+
+  /**
+   * The last position
+   */
+  private int[] mLastPositions;
+  /**
+   * The first position
+   */
+  private int[] mFirstPositions;
+
+
+  /**
+   * The location of last visible item
+   */
+  private int mLastVisibleItemPosition;
+
+  /**
+   * The location of last visible item
+   */
+  private int mFirstVisibleItemPosition;
+
+  /**
+   * The state of scroll status
+   */
+  private int mCurrentScrollState = 0;
+
+  private WeakReference<IOnLoadMoreListener> listener;
+
+  public WXRecyclerViewOnScrollListener(IOnLoadMoreListener listener) {
+    this.listener = new WeakReference<>(listener);
+  }
+
+  @Override
+  public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+    super.onScrollStateChanged(recyclerView, newState);
+    mCurrentScrollState = newState;
+    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+    int visibleItemCount = layoutManager.getChildCount();
+    int totalItemCount = layoutManager.getItemCount();
+
+    if (visibleItemCount != 0) {
+      int bottomOffset = (totalItemCount - mLastVisibleItemPosition - 1) * (recyclerView.getHeight()) / visibleItemCount;
+      if (visibleItemCount > 0 && mCurrentScrollState == RecyclerView.SCROLL_STATE_IDLE) {
+        if (listener != null && listener.get() != null) {
+          listener.get().onLoadMore(bottomOffset);
+        }
+      }
+    }
+  }
+
+  @Override
+  public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+    super.onScrolled(recyclerView, dx, dy);
+    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+    if(listener == null){
+      return;
+    }
+    IOnLoadMoreListener iOnLoadMoreListener = listener.get();
+
+    if(iOnLoadMoreListener!=null) {
+
+      iOnLoadMoreListener.onBeforeScroll(dx, dy);
+
+      if (layoutManager instanceof LinearLayoutManager) {
+        layoutManagerType = LAYOUT_MANAGER_TYPE.LINEAR;
+        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
+        mLastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
+        int firstVisible = linearLayoutManager.findFirstVisibleItemPosition();
+        iOnLoadMoreListener.notifyAppearStateChange(firstVisible
+            , mLastVisibleItemPosition
+            , dx
+            , dy);
+      } else if (layoutManager instanceof GridLayoutManager) {
+        layoutManagerType = LAYOUT_MANAGER_TYPE.GRID;
+        GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
+        mLastVisibleItemPosition = gridLayoutManager.findLastVisibleItemPosition();
+        iOnLoadMoreListener.notifyAppearStateChange(gridLayoutManager.findFirstVisibleItemPosition()
+            , mLastVisibleItemPosition
+            , dx
+            , dy);
+
+      } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+        layoutManagerType = LAYOUT_MANAGER_TYPE.STAGGERED_GRID;
+        StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
+        int newSpanCount = staggeredGridLayoutManager.getSpanCount();
+        if (mLastPositions == null || newSpanCount != mLastPositions.length) {
+          mLastPositions = new int[newSpanCount];
+        }
+        if (mFirstPositions == null || newSpanCount != mFirstPositions.length) {
+          mFirstPositions = new int[newSpanCount];
+        }
+        //avoid crash of support-v7 original bug
+        try{
+          staggeredGridLayoutManager.findFirstVisibleItemPositions(mFirstPositions);
+          mFirstVisibleItemPosition = findMin(mFirstPositions);
+          staggeredGridLayoutManager.findLastVisibleItemPositions(mLastPositions);
+          mLastVisibleItemPosition = findMax(mLastPositions);
+          iOnLoadMoreListener.notifyAppearStateChange(
+              mFirstVisibleItemPosition
+              , mLastVisibleItemPosition
+              , dx
+              , dy);
+
+        }catch(Exception e){
+          e.printStackTrace();
+          WXLogUtils.e(e.toString());
+        }
+
+      } else {
+        throw new RuntimeException(
+            "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
+      }
+    }
+  }
+
+  private int findMax(int[] lastPositions) {
+    int max = lastPositions[0];
+    for (int value : lastPositions) {
+      if (value > max) {
+        max = value;
+      }
+    }
+    return max;
+  }
+
+  private int findMin(int[] firstPositions) {
+    int min = firstPositions[0];
+    for (int value : firstPositions) {
+      if (value < min) {
+        min = value;
+      }
+    }
+    return min;
+  }
+
+  public enum LAYOUT_MANAGER_TYPE {
+    LINEAR,
+    GRID,
+    STAGGERED_GRID
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/circlebar/CircleProgressBar.java b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/circlebar/CircleProgressBar.java
new file mode 100644
index 0000000..cbb581f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/circlebar/CircleProgressBar.java
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.refresh.circlebar;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
+import android.graphics.Shader;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.animation.Animation;
+import android.widget.ImageView;
+
+/**
+ * Modify of android.support.v4
+ */
+@SuppressLint("AppCompatCustomView")
+public class CircleProgressBar extends ImageView {
+
+  private static final int KEY_SHADOW_COLOR = 0x1E000000;
+  private static final int FILL_SHADOW_COLOR = 0x3D000000;
+  private static final float X_OFFSET = 0f;
+  private static final float Y_OFFSET = 1.75f;
+  private static final float SHADOW_RADIUS = 3.5f;
+  private static final int SHADOW_ELEVATION = 4;
+
+  public static final int DEFAULT_CIRCLE_BG_LIGHT = 0xFFFAFAFA;
+  public static final int DEFAULT_CIRCLE_COLOR = 0xFFF00000;
+  private static final int DEFAULT_CIRCLE_DIAMETER = 40;
+  private static final int STROKE_WIDTH_LARGE = 3;
+
+  private Animation.AnimationListener mListener;
+  private int mShadowRadius;
+  private int mBackGroundColor;
+  private int mProgressColor;
+  private int mProgressStokeWidth;
+  private int mArrowWidth;
+  private int mArrowHeight;
+  private int mProgress;
+  private int mMax;
+  private int mDiameter;
+  private int mInnerRadius;
+  private boolean mShowArrow;
+  public MaterialProgressDrawable mProgressDrawable;
+  private ShapeDrawable mBgCircle;
+  private boolean mCircleBackgroundEnabled;
+  private int[] mColors = new int[]{Color.BLACK};
+
+  public CircleProgressBar(Context context) {
+    super(context);
+    init(context, null, 0);
+
+  }
+
+  public CircleProgressBar(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    init(context, attrs, 0);
+
+  }
+
+  public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
+    super(context, attrs, defStyleAttr);
+    init(context, attrs, defStyleAttr);
+  }
+
+  private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+
+    final float density = getContext().getResources().getDisplayMetrics().density;
+    mBackGroundColor = DEFAULT_CIRCLE_BG_LIGHT;
+    mProgressColor = DEFAULT_CIRCLE_COLOR;
+    mColors = new int[]{mProgressColor};
+    mInnerRadius = -1;
+    mProgressStokeWidth = (int) (STROKE_WIDTH_LARGE * density);
+    mArrowWidth =  -1;
+    mArrowHeight = -1;
+    mShowArrow = true;
+    mCircleBackgroundEnabled = true;
+    mProgress = 0;
+    mMax = 100;
+    mProgressDrawable = new MaterialProgressDrawable(getContext(), this);
+    super.setImageDrawable(mProgressDrawable);
+  }
+
+  public void setProgressBackGroundColor(int color) {
+    this.mBackGroundColor = color;
+  }
+
+  private boolean elevationSupported() {
+    return android.os.Build.VERSION.SDK_INT >= 21;
+  }
+
+  @Override
+  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    if (!elevationSupported()) {
+      setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight()
+                                                                   + mShadowRadius * 2);
+    }
+  }
+
+  public int getProgressStokeWidth() {
+    return mProgressStokeWidth;
+  }
+
+  public void setProgressStokeWidth(int mProgressStokeWidth) {
+    final float density = getContext().getResources().getDisplayMetrics().density;
+    this.mProgressStokeWidth = (int) (mProgressStokeWidth * density);
+  }
+
+  @Override
+  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+    super.onLayout(changed, left, top, right, bottom);
+    final float density = getContext().getResources().getDisplayMetrics().density;
+    mDiameter = Math.min(getMeasuredWidth(), getMeasuredHeight());
+    if (mDiameter <= 0) {
+      mDiameter = (int) density * DEFAULT_CIRCLE_DIAMETER;
+    }
+    if (getBackground() == null && mCircleBackgroundEnabled) {
+      final int shadowYOffset = (int) (density * Y_OFFSET);
+      final int shadowXOffset = (int) (density * X_OFFSET);
+      mShadowRadius = (int) (density * SHADOW_RADIUS);
+
+      if (elevationSupported()) {
+        if(mBgCircle == null) {
+          mBgCircle = new ShapeDrawable(new OvalShape());
+        }
+        ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
+      } else {
+        if(!(mBgCircle != null &&
+            mBgCircle.getShape() instanceof  OvalShadow &&
+            ((OvalShadow) mBgCircle.getShape()).mCircleDiameter == (mDiameter - mShadowRadius * 2) &&
+            ((OvalShadow) mBgCircle.getShape()).mShadowRadius == mShadowRadius)) {
+          OvalShape oval = new OvalShadow(mShadowRadius, mDiameter - mShadowRadius * 2);
+          mBgCircle = new ShapeDrawable(oval);
+        }
+        ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, mBgCircle.getPaint());
+        mBgCircle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
+                                            KEY_SHADOW_COLOR);
+        final int padding = (int) mShadowRadius;
+        // set padding so the inner image sits correctly within the shadow.
+        setPadding(padding, padding, padding, padding);
+      }
+      mBgCircle.getPaint().setColor(mBackGroundColor);
+      setBackgroundDrawable(mBgCircle);
+    }
+    mProgressDrawable.setBackgroundColor(mBackGroundColor);
+    mProgressDrawable.setColorSchemeColors(mColors);
+    if (isShowArrow()) {
+      mProgressDrawable.setArrowScale(1f);
+      mProgressDrawable.showArrow(true);
+    }
+    super.setImageDrawable(null);
+    super.setImageDrawable(mProgressDrawable);
+    mProgressDrawable.setAlpha(255);
+    if (getVisibility() == VISIBLE) {
+      mProgressDrawable.setStartEndTrim(0, (float) 0.8);
+    }
+  }
+
+  public boolean isShowArrow() {
+    return mShowArrow;
+  }
+
+  public void setShowArrow(boolean showArrow) {
+    this.mShowArrow = showArrow;
+  }
+
+  public void setAnimationListener(Animation.AnimationListener listener) {
+    mListener = listener;
+  }
+
+  @Override
+  public void onAnimationStart() {
+    super.onAnimationStart();
+    if (mListener != null) {
+      mListener.onAnimationStart(getAnimation());
+    }
+  }
+
+  @Override
+  public void onAnimationEnd() {
+    super.onAnimationEnd();
+    if (mListener != null) {
+      mListener.onAnimationEnd(getAnimation());
+    }
+  }
+
+  /**
+   * Set the colors used in the progress animation. The first
+   * color will also be the color of the bar that grows in response to a user
+   * swipe gesture.
+   *
+   * @param colors
+   */
+  public void setColorSchemeColors(int... colors) {
+    mColors = colors;
+    if (mProgressDrawable != null) {
+      mProgressDrawable.setColorSchemeColors(colors);
+    }
+  }
+
+  /**
+   * Update the background color of the mBgCircle image view.
+   */
+  public void setBackgroundColorResource(int colorRes) {
+    if (getBackground() instanceof ShapeDrawable) {
+      final Resources res = getResources();
+      ((ShapeDrawable) getBackground()).getPaint().setColor(res.getColor(colorRes));
+    }
+  }
+
+  public void setBackgroundColor(int color) {
+    if (getBackground() instanceof ShapeDrawable) {
+      ((ShapeDrawable) getBackground()).getPaint().setColor(color);
+    }
+  }
+
+  public int getMax() {
+    return mMax;
+  }
+
+  public void setMax(int max) {
+    mMax = max;
+  }
+
+  public int getProgress() {
+    return mProgress;
+  }
+
+  public void setProgress(int progress) {
+    if (getMax() > 0) {
+      mProgress = progress;
+    }
+    invalidate();
+  }
+
+  public boolean circleBackgroundEnabled() {
+    return mCircleBackgroundEnabled;
+  }
+
+  public void setCircleBackgroundEnabled(boolean enableCircleBackground) {
+    this.mCircleBackgroundEnabled = enableCircleBackground;
+  }
+
+  @Override
+  protected void onAttachedToWindow() {
+    super.onAttachedToWindow();
+    if (mProgressDrawable != null) {
+      mProgressDrawable.stop();
+      mProgressDrawable.setVisible(getVisibility() == VISIBLE, false);
+    }
+  }
+
+  @Override
+  protected void onDetachedFromWindow() {
+    super.onDetachedFromWindow();
+    if (mProgressDrawable != null) {
+      mProgressDrawable.stop();
+      mProgressDrawable.setVisible(false, false);
+    }
+  }
+
+  private class OvalShadow extends OvalShape {
+
+    private RadialGradient mRadialGradient;
+    private int mShadowRadius;
+    private Paint mShadowPaint;
+    private int mCircleDiameter;
+
+    public OvalShadow(int shadowRadius, int circleDiameter) {
+      super();
+      mShadowPaint = new Paint();
+      mShadowRadius = shadowRadius;
+      mCircleDiameter = circleDiameter;
+      mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,
+                                           mShadowRadius, new int[]{
+          FILL_SHADOW_COLOR, Color.TRANSPARENT
+      }, null, Shader.TileMode.CLAMP);
+      mShadowPaint.setShader(mRadialGradient);
+    }
+
+    @Override
+    public void draw(Canvas canvas, Paint paint) {
+      final int viewWidth = CircleProgressBar.this.getWidth();
+      final int viewHeight = CircleProgressBar.this.getHeight();
+      canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),
+                        mShadowPaint);
+      canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);
+    }
+  }
+
+  public void start() {
+    mProgressDrawable.start();
+  }
+
+  public void setStartEndTrim(float startAngle, float endAngle) {
+    mProgressDrawable.setStartEndTrim(startAngle, endAngle);
+  }
+
+  public void stop() {
+    mProgressDrawable.stop();
+  }
+
+  public void setProgressRotation(float rotation) {
+    mProgressDrawable.setProgressRotation(rotation);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/circlebar/MaterialProgressDrawable.java b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/circlebar/MaterialProgressDrawable.java
new file mode 100644
index 0000000..86716ba
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/circlebar/MaterialProgressDrawable.java
@@ -0,0 +1,797 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.refresh.circlebar;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.Transformation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+
+/**
+ * Copy of android.support.v4
+ */
+class MaterialProgressDrawable extends Drawable implements Animatable {
+
+  private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
+  private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
+
+  private static final float FULL_ROTATION = 1080.0f;
+
+  @Retention(RetentionPolicy.CLASS)
+  @IntDef({LARGE, DEFAULT})
+  public @interface ProgressDrawableSize {
+
+  }
+
+  // Maps to ProgressBar.Large style
+  static final int LARGE = 0;
+  // Maps to ProgressBar default style
+  static final int DEFAULT = 1;
+
+  // Maps to ProgressBar default style
+  private static final int CIRCLE_DIAMETER = 40;
+  private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width
+  private static final float STROKE_WIDTH = 2.5f;
+
+  // Maps to ProgressBar.Large style
+  private static final int CIRCLE_DIAMETER_LARGE = 56;
+  private static final float CENTER_RADIUS_LARGE = 12.5f;
+  private static final float STROKE_WIDTH_LARGE = 3f;
+
+  private final int[] COLORS = new int[]{
+      Color.BLACK
+  };
+
+  /**
+   * The value in the linear interpolator for animating the drawable at which
+   * the color transition should start
+   */
+  private static final float COLOR_START_DELAY_OFFSET = 0.75f;
+  private static final float END_TRIM_START_DELAY_OFFSET = 0.5f;
+  private static final float START_TRIM_DURATION_OFFSET = 0.5f;
+
+  /** The duration of a single progress spin in milliseconds. */
+  private static final int ANIMATION_DURATION = 1332;
+
+  /** The number of points in the progress "star". */
+  private static final float NUM_POINTS = 5f;
+  /** The list of animators operating on this drawable. */
+  private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();
+
+  /** The indicator ring, used to manage animation state. */
+  private final Ring mRing;
+
+  /** Canvas rotation in degrees. */
+  private float mRotation;
+
+  /** Layout info for the arrowhead in dp */
+  private static final int ARROW_WIDTH = 10;
+  private static final int ARROW_HEIGHT = 5;
+  private static final float ARROW_OFFSET_ANGLE = 5;
+
+  /** Layout info for the arrowhead for the large spinner in dp */
+  private static final int ARROW_WIDTH_LARGE = 12;
+  private static final int ARROW_HEIGHT_LARGE = 6;
+  private static final float MAX_PROGRESS_ARC = .8f;
+
+  private Resources mResources;
+  private View mParent;
+  private Animation mAnimation;
+  private float mRotationCount;
+  private double mWidth;
+  private double mHeight;
+  boolean mFinishing;
+
+  public MaterialProgressDrawable(Context context, View parent) {
+    mParent = parent;
+    mResources = context.getResources();
+
+    mRing = new Ring(mCallback);
+    mRing.setColors(COLORS);
+
+    updateSizes(DEFAULT);
+    setupAnimators();
+  }
+
+  private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,
+                                 double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {
+    final Ring ring = mRing;
+    final DisplayMetrics metrics = mResources.getDisplayMetrics();
+    final float screenDensity = metrics.density;
+
+    mWidth = progressCircleWidth * screenDensity;
+    mHeight = progressCircleHeight * screenDensity;
+    ring.setStrokeWidth((float) strokeWidth * screenDensity);
+    ring.setCenterRadius(centerRadius * screenDensity);
+    ring.setColorIndex(0);
+    ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);
+    ring.setInsets((int) mWidth, (int) mHeight);
+  }
+
+  /**
+   * Set the overall size for the progress spinner. This updates the radius
+   * and stroke width of the ring.
+   *
+   * @param size One of {@link MaterialProgressDrawable.LARGE} or
+   *            {@link MaterialProgressDrawable.DEFAULT}
+   */
+  public void updateSizes(@ProgressDrawableSize int size) {
+    if (size == LARGE) {
+      setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,
+                        STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);
+    } else {
+      setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,
+                        ARROW_WIDTH, ARROW_HEIGHT);
+    }
+  }
+
+  /**
+   * @param show Set to true to display the arrowhead on the progress spinner.
+   */
+  public void showArrow(boolean show) {
+    mRing.setShowArrow(show);
+  }
+
+  /**
+   * @param scale Set the scale of the arrowhead for the spinner.
+   */
+  public void setArrowScale(float scale) {
+    mRing.setArrowScale(scale);
+  }
+
+  /**
+   * Set the start and end trim for the progress spinner arc.
+   *
+   * @param startAngle start angle
+   * @param endAngle end angle
+   */
+  public void setStartEndTrim(float startAngle, float endAngle) {
+    mRing.setStartTrim(startAngle);
+    mRing.setEndTrim(endAngle);
+  }
+
+  /**
+   * Set the amount of rotation to apply to the progress spinner.
+   *
+   * @param rotation Rotation is from [0..1]
+   */
+  public void setProgressRotation(float rotation) {
+    mRing.setRotation(rotation);
+  }
+
+  /**
+   * Update the background color of the circle image view.
+   */
+  public void setBackgroundColor(int color) {
+    mRing.setBackgroundColor(color);
+  }
+
+  /**
+   * Set the colors used in the progress animation from color resources.
+   * The first color will also be the color of the bar that grows in response
+   * to a user swipe gesture.
+   *
+   * @param colors
+   */
+  public void setColorSchemeColors(int... colors) {
+    mRing.setColors(colors);
+    mRing.setColorIndex(0);
+  }
+
+  @Override
+  public int getIntrinsicHeight() {
+    return (int) mHeight;
+  }
+
+  @Override
+  public int getIntrinsicWidth() {
+    return (int) mWidth;
+  }
+
+  @Override
+  public void draw(Canvas c) {
+    final Rect bounds = getBounds();
+    final int saveCount = c.save();
+    c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());
+    mRing.draw(c, bounds);
+    c.restoreToCount(saveCount);
+  }
+
+  @Override
+  public void setAlpha(int alpha) {
+    mRing.setAlpha(alpha);
+  }
+
+  public int getAlpha() {
+    return mRing.getAlpha();
+  }
+
+  @Override
+  public void setColorFilter(ColorFilter colorFilter) {
+    mRing.setColorFilter(colorFilter);
+  }
+
+  @SuppressWarnings("unused")
+  void setRotation(float rotation) {
+    mRotation = rotation;
+    invalidateSelf();
+  }
+
+  @SuppressWarnings("unused")
+  private float getRotation() {
+    return mRotation;
+  }
+
+  @Override
+  public int getOpacity() {
+    return PixelFormat.TRANSLUCENT;
+  }
+
+  @Override
+  public boolean isRunning() {
+    final ArrayList<Animation> animators = mAnimators;
+    final int N = animators.size();
+    for (int i = 0; i < N; i++) {
+      final Animation animator = animators.get(i);
+      if (animator.hasStarted() && !animator.hasEnded()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public void start() {
+    mAnimation.reset();
+    mRing.storeOriginals();
+    // Already showing some part of the ring
+    if (mRing.getEndTrim() != mRing.getStartTrim()) {
+      mFinishing = true;
+      mAnimation.setDuration(ANIMATION_DURATION / 2);
+      mParent.startAnimation(mAnimation);
+    } else {
+      mRing.setColorIndex(0);
+      mRing.resetOriginals();
+      mAnimation.setDuration(ANIMATION_DURATION);
+      mParent.startAnimation(mAnimation);
+    }
+  }
+
+  @Override
+  public void stop() {
+    mParent.clearAnimation();
+    setRotation(0);
+    mRing.setShowArrow(false);
+    mRing.setColorIndex(0);
+    mRing.resetOriginals();
+  }
+
+  private float getMinProgressArc(Ring ring) {
+    return (float) Math.toRadians(
+        ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
+  }
+
+  // Adapted from ArgbEvaluator.java
+  private int evaluateColorChange(float fraction, int startValue, int endValue) {
+    int startInt = (Integer) startValue;
+    int startA = (startInt >> 24) & 0xff;
+    int startR = (startInt >> 16) & 0xff;
+    int startG = (startInt >> 8) & 0xff;
+    int startB = startInt & 0xff;
+
+    int endInt = (Integer) endValue;
+    int endA = (endInt >> 24) & 0xff;
+    int endR = (endInt >> 16) & 0xff;
+    int endG = (endInt >> 8) & 0xff;
+    int endB = endInt & 0xff;
+
+    return (int) ((startA + (int) (fraction * (endA - startA))) << 24) |
+           (int) ((startR + (int) (fraction * (endR - startR))) << 16) |
+           (int) ((startG + (int) (fraction * (endG - startG))) << 8) |
+           (int) ((startB + (int) (fraction * (endB - startB))));
+  }
+
+  /**
+   * Update the ring color if this is within the last 25% of the animation.
+   * The new ring color will be a translation from the starting ring color to
+   * the next color.
+   */
+  private void updateRingColor(float interpolatedTime, Ring ring) {
+    if (interpolatedTime > COLOR_START_DELAY_OFFSET) {
+      // scale the interpolatedTime so that the full
+      // transformation from 0 - 1 takes place in the
+      // remaining time
+      ring.setColor(evaluateColorChange((interpolatedTime - COLOR_START_DELAY_OFFSET)
+                                        / (1.0f - COLOR_START_DELAY_OFFSET), ring.getStartingColor(),
+                                        ring.getNextColor()));
+    }
+  }
+
+  private void applyFinishTranslation(float interpolatedTime, Ring ring) {
+    // shrink back down and complete a full rotation before
+    // starting other circles
+    // Rotation goes between [0..1].
+    updateRingColor(interpolatedTime, ring);
+    float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC)
+                                    + 1f);
+    final float minProgressArc = getMinProgressArc(ring);
+    final float startTrim = ring.getStartingStartTrim()
+                            + (ring.getStartingEndTrim() - minProgressArc - ring.getStartingStartTrim())
+                              * interpolatedTime;
+    ring.setStartTrim(startTrim);
+    ring.setEndTrim(ring.getStartingEndTrim());
+    final float rotation = ring.getStartingRotation()
+                           + ((targetRotation - ring.getStartingRotation()) * interpolatedTime);
+    ring.setRotation(rotation);
+  }
+
+  private void setupAnimators() {
+    final Ring ring = mRing;
+    final Animation animation = new Animation() {
+      @Override
+      public void applyTransformation(float interpolatedTime, Transformation t) {
+        if (mFinishing) {
+          applyFinishTranslation(interpolatedTime, ring);
+        } else {
+          // The minProgressArc is calculated from 0 to create an
+          // angle that matches the stroke width.
+          final float minProgressArc = getMinProgressArc(ring);
+          final float startingEndTrim = ring.getStartingEndTrim();
+          final float startingTrim = ring.getStartingStartTrim();
+          final float startingRotation = ring.getStartingRotation();
+
+          updateRingColor(interpolatedTime, ring);
+
+          // Moving the start trim only occurs in the first 50% of a
+          // single ring animation
+          if (interpolatedTime <= START_TRIM_DURATION_OFFSET) {
+            // scale the interpolatedTime so that the full
+            // transformation from 0 - 1 takes place in the
+            // remaining time
+            final float scaledTime = (interpolatedTime)
+                                     / (1.0f - START_TRIM_DURATION_OFFSET);
+            final float startTrim = startingTrim
+                                    + ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR
+                .getInterpolation(scaledTime));
+            ring.setStartTrim(startTrim);
+          }
+
+          // Moving the end trim starts after 50% of a single ring
+          // animation completes
+          if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) {
+            // scale the interpolatedTime so that the full
+            // transformation from 0 - 1 takes place in the
+            // remaining time
+            final float minArc = MAX_PROGRESS_ARC - minProgressArc;
+            float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET)
+                               / (1.0f - START_TRIM_DURATION_OFFSET);
+            final float endTrim = startingEndTrim
+                                  + (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime));
+            ring.setEndTrim(endTrim);
+          }
+
+          final float rotation = startingRotation + (0.25f * interpolatedTime);
+          ring.setRotation(rotation);
+
+          float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime)
+                                + (FULL_ROTATION * (mRotationCount / NUM_POINTS));
+          setRotation(groupRotation);
+        }
+      }
+    };
+    animation.setRepeatCount(Animation.INFINITE);
+    animation.setRepeatMode(Animation.RESTART);
+    animation.setInterpolator(LINEAR_INTERPOLATOR);
+    animation.setAnimationListener(new Animation.AnimationListener() {
+
+      @Override
+      public void onAnimationStart(Animation animation) {
+        mRotationCount = 0;
+      }
+
+      @Override
+      public void onAnimationEnd(Animation animation) {
+        // do nothing
+      }
+
+      @Override
+      public void onAnimationRepeat(Animation animation) {
+        ring.storeOriginals();
+        ring.goToNextColor();
+        ring.setStartTrim(ring.getEndTrim());
+        if (mFinishing) {
+          // finished closing the last ring from the swipe gesture; go
+          // into progress mode
+          mFinishing = false;
+          animation.setDuration(ANIMATION_DURATION);
+          ring.setShowArrow(false);
+        } else {
+          mRotationCount = (mRotationCount + 1) % (NUM_POINTS);
+        }
+      }
+    });
+    mAnimation = animation;
+  }
+
+  private final Callback mCallback = new Callback() {
+    @Override
+    public void invalidateDrawable(Drawable d) {
+      invalidateSelf();
+    }
+
+    @Override
+    public void scheduleDrawable(Drawable d, Runnable what, long when) {
+      scheduleSelf(what, when);
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable d, Runnable what) {
+      unscheduleSelf(what);
+    }
+  };
+
+  private static class Ring {
+
+    private final RectF mTempBounds = new RectF();
+    private final Paint mPaint = new Paint();
+    private final Paint mArrowPaint = new Paint();
+
+    private final Callback mCallback;
+
+    private float mStartTrim = 0.0f;
+    private float mEndTrim = 0.0f;
+    private float mRotation = 0.0f;
+    private float mStrokeWidth = 5.0f;
+    private float mStrokeInset = 2.5f;
+
+    private int[] mColors;
+    // mColorIndex represents the offset into the available mColors that the
+    // progress circle should currently display. As the progress circle is
+    // animating, the mColorIndex moves by one to the next available color.
+    private int mColorIndex;
+    private float mStartingStartTrim;
+    private float mStartingEndTrim;
+    private float mStartingRotation;
+    private boolean mShowArrow;
+    private Path mArrow;
+    private float mArrowScale;
+    private double mRingCenterRadius;
+    private int mArrowWidth;
+    private int mArrowHeight;
+    private int mAlpha;
+    private final Paint mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private int mBackgroundColor;
+    private int mCurrentColor;
+
+    public Ring(Callback callback) {
+      mCallback = callback;
+
+      mPaint.setStrokeCap(Paint.Cap.SQUARE);
+      mPaint.setAntiAlias(true);
+      mPaint.setStyle(Style.STROKE);
+
+      mArrowPaint.setStyle(Style.FILL);
+      mArrowPaint.setAntiAlias(true);
+    }
+
+    public void setBackgroundColor(int color) {
+      mBackgroundColor = color;
+    }
+
+    /**
+     * Set the dimensions of the arrowhead.
+     *
+     * @param width Width of the hypotenuse of the arrow head
+     * @param height Height of the arrow point
+     */
+    public void setArrowDimensions(float width, float height) {
+      mArrowWidth = (int) width;
+      mArrowHeight = (int) height;
+    }
+
+    /**
+     * Draw the progress spinner
+     */
+    public void draw(Canvas c, Rect bounds) {
+      final RectF arcBounds = mTempBounds;
+      arcBounds.set(bounds);
+      arcBounds.inset(mStrokeInset, mStrokeInset);
+
+      final float startAngle = (mStartTrim + mRotation) * 360;
+      final float endAngle = (mEndTrim + mRotation) * 360;
+      float sweepAngle = endAngle - startAngle;
+
+      mPaint.setColor(mCurrentColor);
+      c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint);
+
+      drawTriangle(c, startAngle, sweepAngle, bounds);
+
+      if (mAlpha < 255) {
+        mCirclePaint.setColor(mBackgroundColor);
+        mCirclePaint.setAlpha(255 - mAlpha);
+        c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2,
+                     mCirclePaint);
+      }
+    }
+
+    private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {
+      if (mShowArrow) {
+        if (mArrow == null) {
+          mArrow = new Path();
+          mArrow.setFillType(Path.FillType.EVEN_ODD);
+        } else {
+          mArrow.reset();
+        }
+
+        // Adjust the position of the triangle so that it is inset as
+        // much as the arc, but also centered on the arc.
+        float inset = (int) mStrokeInset / 2 * mArrowScale;
+        float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());
+        float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());
+
+        // Update the path each time. This works around an issue in SKIA
+        // where concatenating a rotation matrix to a scale matrix
+        // ignored a starting negative rotation. This appears to have
+        // been fixed as of API 21.
+        mArrow.moveTo(0, 0);
+        mArrow.lineTo(mArrowWidth * mArrowScale, 0);
+        mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight
+                                                        * mArrowScale));
+        mArrow.offset(x - inset, y);
+        mArrow.close();
+        // draw a triangle
+        mArrowPaint.setColor(mCurrentColor);
+        c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),
+                 bounds.exactCenterY());
+        c.drawPath(mArrow, mArrowPaint);
+      }
+    }
+
+    /**
+     * Set the colors the progress spinner alternates between.
+     *
+     * @param colors Array of integers describing the colors. Must be non-<code>null</code>.
+     */
+    public void setColors(@NonNull int[] colors) {
+      mColors = colors;
+      // if colors are reset, make sure to reset the color index as well
+      setColorIndex(0);
+    }
+
+    /**
+     * Set the absolute color of the progress spinner. This is should only
+     * be used when animating between current and next color when the
+     * spinner is rotating.
+     *
+     * @param color int describing the color.
+     */
+    public void setColor(int color) {
+      mCurrentColor = color;
+    }
+
+    /**
+     * @param index Index into the color array of the color to display in
+     *            the progress spinner.
+     */
+    public void setColorIndex(int index) {
+      mColorIndex = index;
+      mCurrentColor = mColors[mColorIndex];
+    }
+
+    /**
+     * @return int describing the next color the progress spinner should use when drawing.
+     */
+    public int getNextColor() {
+      return mColors[getNextColorIndex()];
+    }
+
+    private int getNextColorIndex() {
+      return (mColorIndex + 1) % (mColors.length);
+    }
+
+    /**
+     * Proceed to the next available ring color. This will automatically
+     * wrap back to the beginning of colors.
+     */
+    public void goToNextColor() {
+      setColorIndex(getNextColorIndex());
+    }
+
+    public void setColorFilter(ColorFilter filter) {
+      mPaint.setColorFilter(filter);
+      invalidateSelf();
+    }
+
+    /**
+     * @param alpha Set the alpha of the progress spinner and associated arrowhead.
+     */
+    public void setAlpha(int alpha) {
+      mAlpha = alpha;
+    }
+
+    /**
+     * @return Current alpha of the progress spinner and arrowhead.
+     */
+    public int getAlpha() {
+      return mAlpha;
+    }
+
+    /**
+     * @param strokeWidth Set the stroke width of the progress spinner in pixels.
+     */
+    public void setStrokeWidth(float strokeWidth) {
+      mStrokeWidth = strokeWidth;
+      mPaint.setStrokeWidth(strokeWidth);
+      invalidateSelf();
+    }
+
+    @SuppressWarnings("unused")
+    public float getStrokeWidth() {
+      return mStrokeWidth;
+    }
+
+    @SuppressWarnings("unused")
+    public void setStartTrim(float startTrim) {
+      mStartTrim = startTrim;
+      invalidateSelf();
+    }
+
+    @SuppressWarnings("unused")
+    public float getStartTrim() {
+      return mStartTrim;
+    }
+
+    public float getStartingStartTrim() {
+      return mStartingStartTrim;
+    }
+
+    public float getStartingEndTrim() {
+      return mStartingEndTrim;
+    }
+
+    public int getStartingColor() {
+      return mColors[mColorIndex];
+    }
+
+    @SuppressWarnings("unused")
+    public void setEndTrim(float endTrim) {
+      mEndTrim = endTrim;
+      invalidateSelf();
+    }
+
+    @SuppressWarnings("unused")
+    public float getEndTrim() {
+      return mEndTrim;
+    }
+
+    @SuppressWarnings("unused")
+    public void setRotation(float rotation) {
+      mRotation = rotation;
+      invalidateSelf();
+    }
+
+    @SuppressWarnings("unused")
+    public float getRotation() {
+      return mRotation;
+    }
+
+    public void setInsets(int width, int height) {
+      final float minEdge = (float) Math.min(width, height);
+      float insets;
+      if (mRingCenterRadius <= 0 || minEdge < 0) {
+        insets = (float) Math.ceil(mStrokeWidth / 2.0f);
+      } else {
+        insets = (float) (minEdge / 2.0f - mRingCenterRadius);
+      }
+      mStrokeInset = insets;
+    }
+
+    @SuppressWarnings("unused")
+    public float getInsets() {
+      return mStrokeInset;
+    }
+
+    /**
+     * @param centerRadius Inner radius in px of the circle the progress
+     *            spinner arc traces.
+     */
+    public void setCenterRadius(double centerRadius) {
+      mRingCenterRadius = centerRadius;
+    }
+
+    public double getCenterRadius() {
+      return mRingCenterRadius;
+    }
+
+    /**
+     * @param show Set to true to show the arrow head on the progress spinner.
+     */
+    public void setShowArrow(boolean show) {
+      if (mShowArrow != show) {
+        mShowArrow = show;
+        invalidateSelf();
+      }
+    }
+
+    /**
+     * @param scale Set the scale of the arrowhead for the spinner.
+     */
+    public void setArrowScale(float scale) {
+      if (scale != mArrowScale) {
+        mArrowScale = scale;
+        invalidateSelf();
+      }
+    }
+
+    /**
+     * @return The amount the progress spinner is currently rotated, between [0..1].
+     */
+    public float getStartingRotation() {
+      return mStartingRotation;
+    }
+
+    /**
+     * If the start / end trim are offset to begin with, store them so that
+     * animation starts from that offset.
+     */
+    public void storeOriginals() {
+      mStartingStartTrim = mStartTrim;
+      mStartingEndTrim = mEndTrim;
+      mStartingRotation = mRotation;
+    }
+
+    /**
+     * Reset the progress spinner to default rotation, start and end angles.
+     */
+    public void resetOriginals() {
+      mStartingStartTrim = 0;
+      mStartingEndTrim = 0;
+      mStartingRotation = 0;
+      setStartTrim(0);
+      setEndTrim(0);
+      setRotation(0);
+    }
+
+    private void invalidateSelf() {
+      mCallback.invalidateDrawable(null);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/core/WXRefreshView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/core/WXRefreshView.java
new file mode 100644
index 0000000..1edc5b7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/core/WXRefreshView.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.refresh.core;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import org.apache.weex.common.WXThread;
+import org.apache.weex.ui.view.refresh.circlebar.CircleProgressBar;
+
+public class WXRefreshView extends FrameLayout {
+
+  private CircleProgressBar circleProgressBar;
+  private LinearLayout linearLayout;
+
+  public WXRefreshView(Context context) {
+    super(context);
+    setupViews();
+  }
+
+  public WXRefreshView(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    setupViews();
+  }
+
+  public WXRefreshView(Context context, AttributeSet attrs, int defStyleAttr) {
+    super(context, attrs, defStyleAttr);
+    setupViews();
+  }
+
+  private void setupViews() {
+    linearLayout = new LinearLayout(getContext());
+    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams
+            .MATCH_PARENT,FrameLayout
+            .LayoutParams.MATCH_PARENT);
+    linearLayout.setOrientation(LinearLayout.VERTICAL);
+    linearLayout.setGravity(Gravity.CENTER);
+    addView(linearLayout,lp);
+  }
+
+  public void setContentGravity(int gravity) {
+    if (linearLayout != null) {
+      linearLayout.setGravity(gravity);
+    }
+  }
+
+  /**
+   * Setting refresh view or loading view
+   *
+   * @param view refresh or loading
+   */
+  public void setRefreshView(final View view) {
+    if (view == null)
+      return;
+    post(WXThread.secure(new Runnable() {
+      @Override
+      public void run() {
+        View child = null;
+        View temp = view;
+        if (view.getParent() != null) {
+          ((ViewGroup) view.getParent()).removeView(view);
+        }
+        for (int i = 0;i<((ViewGroup)temp).getChildCount(); i++) {
+          child = ((ViewGroup) temp).getChildAt(i);
+          if (child instanceof CircleProgressBar)
+            circleProgressBar = (CircleProgressBar) child;
+        }
+        linearLayout.addView(temp);
+      }
+    }));
+  }
+
+  /**
+   * Set loading_indicator bgColor
+   *
+   * @param color
+   */
+  public void setProgressBgColor(int color) {
+    if (circleProgressBar != null) {
+      circleProgressBar.setBackgroundColor(color);
+    }
+  }
+
+  /**
+   * Set loading_indicator color
+   *
+   * @param color
+   */
+  public void setProgressColor(int color) {
+    if (circleProgressBar != null) {
+      circleProgressBar.setColorSchemeColors(color);
+    }
+  }
+
+  protected void startAnimation() {
+    if (circleProgressBar != null) {
+      circleProgressBar.start();
+    }
+  }
+
+  /**
+   * Set the start and end trim for the progress spinner arc.
+   *
+   * @param startAngle start angle
+   * @param endAngle end angle
+   */
+  public void setStartEndTrim(float startAngle, float endAngle) {
+    if (circleProgressBar != null) {
+      circleProgressBar.setStartEndTrim(startAngle, endAngle);
+    }
+  }
+
+  protected void stopAnimation() {
+    if (circleProgressBar != null) {
+      circleProgressBar.stop();
+    }
+  }
+
+  /**
+   * Set the amount of rotation to apply to the progress spinner.
+   *
+   * @param rotation Rotation is from [0..1]
+   */
+  public void setProgressRotation(float rotation) {
+    if (circleProgressBar != null)
+      circleProgressBar.setProgressRotation(rotation);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/core/WXSwipeLayout.java b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/core/WXSwipeLayout.java
new file mode 100644
index 0000000..67f9333
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/core/WXSwipeLayout.java
@@ -0,0 +1,854 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.refresh.core;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.v4.view.NestedScrollingChild;
+import android.support.v4.view.NestedScrollingChildHelper;
+import android.support.v4.view.NestedScrollingParent;
+import android.support.v4.view.NestedScrollingParentHelper;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.ViewParentCompat;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.AbsListView;
+import android.widget.FrameLayout;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class WXSwipeLayout extends FrameLayout implements NestedScrollingParent, NestedScrollingChild {
+
+  private NestedScrollingParentHelper mNestedScrollingParentHelper;
+  private NestedScrollingChildHelper mNestedScrollingChildHelper;
+  private final int[] mParentScrollConsumed = new int[2];
+  private final int[] mParentOffsetInWindow = new int[2];
+  private boolean mNestedScrollInProgress;
+  private WXOnRefreshListener onRefreshListener;
+  private WXOnLoadingListener onLoadingListener;
+
+  private ViewParent mNestedScrollAcceptedParent;
+
+  private final List<OnRefreshOffsetChangedListener> mRefreshOffsetChangedListeners = new LinkedList<>();
+
+  public interface OnRefreshOffsetChangedListener {
+    void onOffsetChanged(int verticalOffset);
+  }
+
+  /**
+   * On refresh Callback, call on start refresh
+   */
+  public interface WXOnRefreshListener {
+
+    void onRefresh();
+
+    void onPullingDown(float dy, int pullOutDistance, float viewHeight);
+  }
+
+  /**
+   * On loadmore Callback, call on start loadmore
+   */
+  public interface WXOnLoadingListener {
+
+    void onLoading();
+    void onPullingUp(float dy, int pullOutDistance, float viewHeight);
+  }
+
+  static class WXRefreshAnimatorListener implements Animator.AnimatorListener {
+
+    @Override
+    public void onAnimationStart(Animator animation) {
+    }
+
+    @Override
+    public void onAnimationEnd(Animator animation) {
+    }
+
+    @Override
+    public void onAnimationCancel(Animator animation) {
+    }
+
+    @Override
+    public void onAnimationRepeat(Animator animation) {
+    }
+  }
+
+  private WXRefreshView headerView;
+  private WXRefreshView footerView;
+  private View mTargetView;
+
+  private static final int INVALID = -1;
+  private static final int PULL_REFRESH = 0;
+  private static final int LOAD_MORE = 1;
+
+  // Enable PullRefresh and Loadmore
+  private boolean mPullRefreshEnable = false;
+  private boolean mPullLoadEnable = false;
+
+  // Is Refreshing
+  volatile private boolean mRefreshing = false;
+
+  // RefreshView Height
+  private volatile float refreshViewHeight = 0;
+  private volatile float loadingViewHeight = 0;
+
+  // RefreshView Over Flow Height
+  private volatile float refreshViewFlowHeight = 0;
+  private volatile float loadingViewFlowHeight = 0;
+
+  private static final float overFlow = 1.0f;
+
+  private static final float DAMPING = 0.4f;
+
+  // Drag Action
+  private int mCurrentAction = -1;
+  private boolean isConfirm = false;
+
+  // RefreshView Attrs
+  private int mRefreshViewBgColor;
+  private int mProgressBgColor;
+  private int mProgressColor;
+
+  public WXSwipeLayout(Context context) {
+    super(context);
+    initAttrs(context, null);
+  }
+
+  public WXSwipeLayout(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    initAttrs(context, attrs);
+  }
+
+  public WXSwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+    super(context, attrs, defStyleAttr);
+    initAttrs(context, attrs);
+  }
+
+  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+  public WXSwipeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    super(context, attrs, defStyleAttr, defStyleRes);
+    initAttrs(context, attrs);
+  }
+
+  private void initAttrs(Context context, AttributeSet attrs) {
+
+    if (getChildCount() > 1) {
+      throw new RuntimeException("WXSwipeLayout should not have more than one child");
+    }
+
+    mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
+    mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
+    setNestedScrollingEnabled(false);
+
+    if (isInEditMode() && attrs == null) {
+      return;
+    }
+
+    mRefreshViewBgColor = Color.TRANSPARENT;
+    mProgressBgColor = Color.TRANSPARENT;
+    mProgressColor = Color.RED;
+  }
+
+  @Override
+  protected void onAttachedToWindow() {
+    super.onAttachedToWindow();
+    if(mTargetView == null && getChildCount() > 0){
+      mTargetView = getChildAt(0);
+    }
+    if(mTargetView != null){
+      if(headerView == null || footerView == null){
+        setRefreshView();
+      }
+    }
+  }
+
+
+  public void addTargetView(View mInnerView){
+    this.addView(mInnerView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
+    setRefreshView();
+  }
+  /**
+   * Init refresh view or loading view
+   */
+  private void setRefreshView() {
+    // SetUp HeaderView
+    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 0);
+    headerView = new WXRefreshView(getContext());
+    headerView.setStartEndTrim(0, 0.75f);
+    headerView.setBackgroundColor(mRefreshViewBgColor);
+    headerView.setProgressBgColor(mProgressBgColor);
+    headerView.setProgressColor(mProgressColor);
+    headerView.setContentGravity(Gravity.BOTTOM);
+    addView(headerView, lp);
+
+    // SetUp FooterView
+    lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 0);
+    lp.gravity = Gravity.BOTTOM;
+    footerView = new WXRefreshView(getContext());
+    footerView.setStartEndTrim(0.5f, 1.25f);
+    footerView.setBackgroundColor(mRefreshViewBgColor);
+    footerView.setProgressBgColor(mProgressBgColor);
+    footerView.setProgressColor(mProgressColor);
+    footerView.setContentGravity(Gravity.TOP);
+    addView(footerView, lp);
+  }
+
+  @Override
+  public boolean onInterceptTouchEvent(MotionEvent ev) {
+    if ((!mPullRefreshEnable && !mPullLoadEnable)) {
+      return false;
+    }
+    if (!isEnabled() || canChildScrollUp()
+            || mRefreshing || mNestedScrollInProgress) {
+      // Fail fast if we're not in a state where a swipe is possible
+      return false;
+    }
+
+    return super.onInterceptTouchEvent(ev);
+  }
+
+  // NestedScrollingChild
+
+  @Override
+  public void setNestedScrollingEnabled(boolean enabled) {
+    mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
+  }
+
+  @Override
+  public boolean isNestedScrollingEnabled() {
+    return mNestedScrollingChildHelper.isNestedScrollingEnabled();
+  }
+
+  @Override
+  public boolean startNestedScroll(int axes) {
+    boolean result = mNestedScrollingChildHelper.startNestedScroll(axes);
+    if(result){
+      if(mNestedScrollAcceptedParent == null){
+        ViewParent parent  = this.getParent();
+        View child = this;
+        while (parent != null) {
+          if (ViewParentCompat.onStartNestedScroll(parent, child, this, axes)){
+            mNestedScrollAcceptedParent = parent;
+            break;
+          }
+          if(parent instanceof  View){
+            child = (View) parent;
+          }
+          parent = parent.getParent();
+        }
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public void stopNestedScroll() {
+    mNestedScrollingChildHelper.stopNestedScroll();
+    if(mNestedScrollAcceptedParent != null){
+      mNestedScrollAcceptedParent = null;
+    }
+  }
+
+  @Override
+  public boolean hasNestedScrollingParent() {
+    return mNestedScrollingChildHelper.hasNestedScrollingParent();
+  }
+
+  @Override
+  public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
+                                      int dyUnconsumed, int[] offsetInWindow) {
+    return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
+            dxUnconsumed, dyUnconsumed, offsetInWindow);
+  }
+
+  @Override
+  public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+    return mNestedScrollingChildHelper.dispatchNestedPreScroll(
+            dx, dy, consumed, offsetInWindow);
+  }
+
+
+
+  @Override
+  public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
+    return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
+  }
+
+  @Override
+  public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
+    return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
+  }
+
+  /*********************************** NestedScrollParent *************************************/
+
+
+  @Override
+  public boolean onNestedPreFling(View target, float velocityX,
+                                  float velocityY) {
+    if(isNestedScrollingEnabled()) {
+      return dispatchNestedPreFling(velocityX, velocityY);
+    }
+    return  false;
+  }
+
+  @Override
+  public boolean onNestedFling(View target, float velocityX, float velocityY,
+                               boolean consumed) {
+    if(isNestedScrollingEnabled()) {
+      return dispatchNestedFling(velocityX, velocityY, consumed);
+    }
+    return  false;
+  }
+
+  @Override
+  public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+    boolean result =  isEnabled()  && !mRefreshing
+            && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
+
+    return  result;
+  }
+
+  @Override
+  public void onNestedScrollAccepted(View child, View target, int axes) {
+    mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
+    if(isNestedScrollingEnabled()){
+      startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
+      mNestedScrollInProgress = true;
+    }
+  }
+
+
+  /**
+   * With child view to processing move events
+   * @param target the child view
+   * @param dx move x
+   * @param dy move y
+   * @param consumed parent consumed move distance
+   */
+  @Override
+  public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+    // Now let our nested parent consume the leftovers
+    final int[] parentConsumed = mParentScrollConsumed;
+    if(isNestedScrollingEnabled()){
+      if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
+        consumed[0] += parentConsumed[0];
+        consumed[1] += parentConsumed[1];
+        return;
+      }
+    }
+    if ((!mPullRefreshEnable && !mPullLoadEnable)) {
+      return;
+    }
+
+    /**
+     * when in nest-scroll, list canChildScrollUp() false,
+     * maybe parent scroll can scroll up
+     * */
+    if(!canChildScrollUp() && isNestedScrollingEnabled()){
+      if(mNestedScrollAcceptedParent != null && mNestedScrollAcceptedParent != mTargetView){
+        ViewGroup group = (ViewGroup) mNestedScrollAcceptedParent;
+        if(group.getChildCount() > 0){
+          int count = group.getChildCount();
+          for(int i=0; i<count; i++){
+            View view  = group.getChildAt(i);
+            if(view.getVisibility() != View.GONE && view.getMeasuredHeight() > 0){
+              if(view.getTop() < 0){
+                return;
+              }else{
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+
+
+
+    int spinnerDy = (int) calculateDistanceY(target, dy);
+
+    mRefreshing = false;
+
+    if (!isConfirm) {
+      if (spinnerDy < 0 && !canChildScrollUp()) {
+        mCurrentAction = PULL_REFRESH;
+        isConfirm = true;
+      } else if (spinnerDy > 0 && !canChildScrollDown() && (!mRefreshing)) {
+        mCurrentAction = LOAD_MORE;
+        isConfirm = true;
+      }
+    }
+
+    if (moveSpinner(-spinnerDy)) {
+      if (!canChildScrollUp() && mPullRefreshEnable
+              && mTargetView.getTranslationY() > 0
+              && dy > 0) {
+        consumed[1] += dy;
+      }else if (!canChildScrollDown() && mPullLoadEnable
+              && mTargetView.getTranslationY() < 0
+              && dy < 0){
+        consumed[1] += dy;
+      }else{
+        consumed[1] += spinnerDy;
+      }
+    }
+  }
+
+  @Override
+  public int getNestedScrollAxes() {
+    return mNestedScrollingParentHelper.getNestedScrollAxes();
+  }
+
+
+  /**
+   * Callback on TouchEvent.ACTION_CANCLE or TouchEvent.ACTION_UP
+   * handler : refresh or loading
+   * @param child : child view of SwipeLayout,RecyclerView or Scroller
+   */
+  @Override
+  public void onStopNestedScroll(View child) {
+    mNestedScrollingParentHelper.onStopNestedScroll(child);
+    handlerAction();
+    if(isNestedScrollingEnabled()) {
+      mNestedScrollInProgress = true;
+      stopNestedScroll();
+    }
+  }
+
+
+  @Override
+  public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
+    if(isNestedScrollingEnabled()) {
+      dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, mParentOffsetInWindow);
+    }
+  }
+
+
+
+
+
+  private double calculateDistanceY(View target, int dy) {
+    int viewHeight = target.getMeasuredHeight();
+    double ratio = (viewHeight - Math.abs(target.getY())) / 1.0d / viewHeight * DAMPING;
+    if (ratio <= 0.01d) {
+      //Filter tiny scrolling action
+      ratio = 0.01d;
+    }
+    return ratio * dy;
+  }
+
+  /**
+   * Adjust the refresh or loading view according to the size of the gesture
+   *
+   * @param distanceY move distance of Y
+   */
+  private boolean moveSpinner(float distanceY) {
+    if (mRefreshing) {
+      return false;
+    }
+
+    if (!canChildScrollUp() && mPullRefreshEnable && mCurrentAction == PULL_REFRESH) {
+      // Pull Refresh
+      LayoutParams lp = (LayoutParams) headerView.getLayoutParams();
+      lp.height += distanceY;
+      if (lp.height < 0) {
+        lp.height = 0;
+      }
+
+      if (lp.height == 0) {
+        isConfirm = false;
+        mCurrentAction = INVALID;
+      }
+      headerView.setLayoutParams(lp);
+      onRefreshListener.onPullingDown(distanceY, lp.height, refreshViewFlowHeight);
+      notifyOnRefreshOffsetChangedListener(lp.height);
+      headerView.setProgressRotation(lp.height / refreshViewFlowHeight);
+      moveTargetView(lp.height);
+      return true;
+    } else if (!canChildScrollDown() && mPullLoadEnable && mCurrentAction == LOAD_MORE) {
+      // Load more
+      LayoutParams lp = (LayoutParams) footerView.getLayoutParams();
+      lp.height -= distanceY;
+      if (lp.height < 0) {
+        lp.height = 0;
+      }
+
+      if (lp.height == 0) {
+        isConfirm = false;
+        mCurrentAction = INVALID;
+      }
+      footerView.setLayoutParams(lp);
+      onLoadingListener.onPullingUp(distanceY, lp.height, loadingViewFlowHeight);
+      footerView.setProgressRotation(lp.height / loadingViewFlowHeight);
+      moveTargetView(-lp.height);
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Adjust contentView(Scroller or List) at refresh or loading time
+   * @param h Height of refresh view or loading view
+   */
+  private void moveTargetView(float h) {
+    mTargetView.setTranslationY(h);
+  }
+
+  /**
+   * Decide on the action refresh or loadmore
+   */
+  private void handlerAction() {
+
+    if (isRefreshing()) {
+      return;
+    }
+    isConfirm = false;
+
+    LayoutParams lp;
+    if (mPullRefreshEnable && mCurrentAction == PULL_REFRESH) {
+      lp = (LayoutParams) headerView.getLayoutParams();
+      if (lp.height >= refreshViewHeight) {
+        startRefresh(lp.height);
+      } else if (lp.height > 0) {
+        resetHeaderView(lp.height);
+      } else {
+        resetRefreshState();
+      }
+    }
+
+    if (mPullLoadEnable && mCurrentAction == LOAD_MORE) {
+      lp = (LayoutParams) footerView.getLayoutParams();
+      if (lp.height >= loadingViewHeight) {
+        startLoadmore(lp.height);
+      } else if (lp.height > 0) {
+        resetFootView(lp.height);
+      } else {
+        resetLoadmoreState();
+      }
+    }
+  }
+
+  /**
+   * Start Refresh
+   * @param headerViewHeight
+   */
+  private void startRefresh(int headerViewHeight) {
+    mRefreshing = true;
+    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, refreshViewHeight);
+    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+      @Override
+      public void onAnimationUpdate(ValueAnimator animation) {
+        LayoutParams lp = (LayoutParams) headerView.getLayoutParams();
+        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
+        notifyOnRefreshOffsetChangedListener(lp.height);
+        headerView.setLayoutParams(lp);
+        moveTargetView(lp.height);
+      }
+    });
+    animator.addListener(new WXRefreshAnimatorListener() {
+      @Override
+      public void onAnimationEnd(Animator animation) {
+        headerView.startAnimation();
+        //TODO updateLoadText
+        if (onRefreshListener != null) {
+          onRefreshListener.onRefresh();
+        }
+      }
+    });
+    animator.setDuration(300);
+    animator.start();
+  }
+
+  /**
+   * Reset refresh state
+   * @param headerViewHeight
+   */
+  private void resetHeaderView(int headerViewHeight) {
+    headerView.stopAnimation();
+    headerView.setStartEndTrim(0, 0.75f);
+    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, 0);
+    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+      @Override
+      public void onAnimationUpdate(ValueAnimator animation) {
+        LayoutParams lp = (LayoutParams) headerView.getLayoutParams();
+        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
+        notifyOnRefreshOffsetChangedListener(lp.height);
+        headerView.setLayoutParams(lp);
+        moveTargetView(lp.height);
+      }
+    });
+    animator.addListener(new WXRefreshAnimatorListener() {
+      @Override
+      public void onAnimationEnd(Animator animation) {
+        resetRefreshState();
+
+      }
+    });
+    animator.setDuration(300);
+    animator.start();
+  }
+
+  private void resetRefreshState() {
+    mRefreshing = false;
+    isConfirm = false;
+    mCurrentAction = -1;
+    //TODO updateLoadText
+  }
+
+  /**
+   * Start loadmore
+   * @param headerViewHeight
+   */
+  private void startLoadmore(int headerViewHeight) {
+    mRefreshing = true;
+    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, loadingViewHeight);
+    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+      @Override
+      public void onAnimationUpdate(ValueAnimator animation) {
+        LayoutParams lp = (LayoutParams) footerView.getLayoutParams();
+        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
+        footerView.setLayoutParams(lp);
+        moveTargetView(-lp.height);
+      }
+    });
+    animator.addListener(new WXRefreshAnimatorListener() {
+      @Override
+      public void onAnimationEnd(Animator animation) {
+        footerView.startAnimation();
+        //TODO updateLoadText
+        if (onLoadingListener != null) {
+          onLoadingListener.onLoading();
+        }
+      }
+    });
+    animator.setDuration(300);
+    animator.start();
+  }
+
+  /**
+   * Reset loadmore state
+   * @param headerViewHeight
+   */
+  private void resetFootView(int headerViewHeight) {
+    footerView.stopAnimation();
+    footerView.setStartEndTrim(0.5f, 1.25f);
+    ValueAnimator animator = ValueAnimator.ofFloat(headerViewHeight, 0);
+    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+      @Override
+      public void onAnimationUpdate(ValueAnimator animation) {
+        LayoutParams lp = (LayoutParams) footerView.getLayoutParams();
+        lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue();
+        footerView.setLayoutParams(lp);
+        moveTargetView(-lp.height);
+      }
+    });
+    animator.addListener(new WXRefreshAnimatorListener() {
+      @Override
+      public void onAnimationEnd(Animator animation) {
+        resetLoadmoreState();
+
+      }
+    });
+    animator.setDuration(300);
+    animator.start();
+  }
+
+  private void resetLoadmoreState() {
+    mRefreshing = false;
+    isConfirm = false;
+    mCurrentAction = -1;
+    //TODO updateLoadText
+  }
+
+  /**
+   * Whether child view can scroll up
+   * @return
+   */
+  @SuppressLint("ObsoleteSdkInt")
+  public boolean canChildScrollUp() {
+    if (mTargetView == null) {
+      return false;
+    }
+    if (Build.VERSION.SDK_INT < 14) {
+      //The minimum version of Android platform that Weex supports is API 14,
+      //so this block should never enter.
+      if (mTargetView instanceof AbsListView) {
+        final AbsListView absListView = (AbsListView) mTargetView;
+        return absListView.getChildCount() > 0
+                && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
+                .getTop() < absListView.getPaddingTop());
+      } else {
+        return ViewCompat.canScrollVertically(mTargetView, -1) || mTargetView.getScrollY() > 0;
+      }
+    } else {
+      return ViewCompat.canScrollVertically(mTargetView, -1);
+    }
+  }
+
+  /**
+   * Whether child view can scroll down
+   * @return
+   */
+  @SuppressLint("ObsoleteSdkInt")
+  public boolean canChildScrollDown() {
+    if (mTargetView == null) {
+      return false;
+    }
+    if (Build.VERSION.SDK_INT < 14) {
+      //The minimum version of Android platform that Weex supports is API 14,
+      //so this block should never enter.
+      if (mTargetView instanceof AbsListView) {
+        final AbsListView absListView = (AbsListView) mTargetView;
+        if (absListView.getChildCount() > 0) {
+          int lastChildBottom = absListView.getChildAt(absListView.getChildCount() - 1)
+                  .getBottom();
+          return absListView.getLastVisiblePosition() == absListView.getAdapter().getCount() - 1
+                  && lastChildBottom <= absListView.getMeasuredHeight();
+        } else {
+          return false;
+        }
+
+      } else {
+        return ViewCompat.canScrollVertically(mTargetView, 1) || mTargetView.getScrollY() > 0;
+      }
+    } else {
+      return ViewCompat.canScrollVertically(mTargetView, 1);
+    }
+  }
+
+  public float dipToPx(Context context, float value) {
+    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, metrics);
+  }
+
+  public void setOnLoadingListener(WXOnLoadingListener onLoadingListener) {
+    this.onLoadingListener = onLoadingListener;
+  }
+
+  public void setOnRefreshListener(WXOnRefreshListener onRefreshListener) {
+    this.onRefreshListener = onRefreshListener;
+  }
+
+  @SuppressWarnings("unused")
+  public void addOnRefreshOffsetChangedListener(@Nullable OnRefreshOffsetChangedListener listener) {
+    if(listener != null && !mRefreshOffsetChangedListeners.contains(listener)) {
+      mRefreshOffsetChangedListeners.add(listener);
+    }
+  }
+
+  @SuppressWarnings("unused")
+  public boolean removeOnRefreshOffsetChangedListener(@Nullable OnRefreshOffsetChangedListener listener) {
+    if(listener != null) {
+      return mRefreshOffsetChangedListeners.remove(listener);
+    }
+    return false;
+  }
+
+  private void notifyOnRefreshOffsetChangedListener(int verticalOffset) {
+    int size = mRefreshOffsetChangedListeners.size();
+    OnRefreshOffsetChangedListener listener;
+    for (int i=0; i<size; i++) {
+      if(i >= mRefreshOffsetChangedListeners.size()){
+        break;
+      }
+      listener = mRefreshOffsetChangedListeners.get(i);
+
+      if (listener != null) {
+        listener.onOffsetChanged(verticalOffset);
+      }
+    }
+  }
+
+  /**
+   * Callback on refresh finish
+   */
+  public void finishPullRefresh() {
+    if (mCurrentAction == PULL_REFRESH) {
+      resetHeaderView(headerView == null ? 0 : headerView.getMeasuredHeight());
+    }
+  }
+
+  /**
+   * Callback on loadmore finish
+   */
+  public void finishPullLoad() {
+    if (mCurrentAction == LOAD_MORE) {
+      resetFootView(footerView == null ? 0 : footerView.getMeasuredHeight());
+    }
+  }
+
+  public WXRefreshView getHeaderView() {
+    return headerView;
+  }
+
+  public WXRefreshView getFooterView() {
+    return footerView;
+  }
+
+  public boolean isPullLoadEnable() {
+    return mPullLoadEnable;
+  }
+
+  public void setPullLoadEnable(boolean mPullLoadEnable) {
+    this.mPullLoadEnable = mPullLoadEnable;
+  }
+
+  public boolean isPullRefreshEnable() {
+    return mPullRefreshEnable;
+  }
+
+  public void setPullRefreshEnable(boolean mPullRefreshEnable) {
+    this.mPullRefreshEnable = mPullRefreshEnable;
+  }
+
+  public boolean isRefreshing() {
+    return mRefreshing;
+  }
+
+  public void setRefreshHeight(int height) {
+    refreshViewHeight = height;
+    refreshViewFlowHeight = refreshViewHeight * overFlow;
+  }
+
+  public void setLoadingHeight(int height) {
+    loadingViewHeight = height;
+    loadingViewFlowHeight = loadingViewHeight * overFlow;
+  }
+
+  public void setRefreshBgColor(int color) {
+    headerView.setBackgroundColor(color);
+  }
+
+  public void setLoadingBgColor(int color) {
+    footerView.setBackgroundColor(color);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BaseBounceView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BaseBounceView.java
new file mode 100644
index 0000000..0e6070a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BaseBounceView.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.refresh.wrapper;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.v7.widget.OrientationHelper;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import org.apache.weex.common.Constants;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.view.WXLoadingLayout;
+import org.apache.weex.ui.view.WXRefreshLayout;
+import org.apache.weex.ui.view.refresh.core.WXRefreshView;
+import org.apache.weex.ui.view.refresh.core.WXSwipeLayout;
+import org.apache.weex.utils.WXResourceUtils;
+import org.apache.weex.utils.WXUtils;
+
+/**
+ * BounceView(SwipeLayout) contains Scroller/List and refresh/loading view
+ * @param <T> InnerView
+ */
+public abstract class BaseBounceView<T extends View> extends FrameLayout {
+
+    private int mOrientation = OrientationHelper.VERTICAL;
+    protected WXSwipeLayout swipeLayout;
+    private T mInnerView;
+
+    public BaseBounceView(Context context,int orientation) {
+        this(context, null,orientation);
+    }
+
+    public BaseBounceView(Context context, AttributeSet attrs,int orientation) {
+        super(context, attrs);
+        mOrientation = orientation;
+    }
+
+    public int getOrientation(){
+        return mOrientation;
+    }
+
+    public void init(Context context) {
+        createBounceView(context);
+    }
+
+    boolean isVertical(){
+        return mOrientation==OrientationHelper.VERTICAL;
+    }
+
+    public void setOnRefreshListener(WXSwipeLayout.WXOnRefreshListener onRefreshListener) {
+        if (swipeLayout != null)
+            swipeLayout.setOnRefreshListener(onRefreshListener);
+    }
+
+    public void setOnLoadingListener(WXSwipeLayout.WXOnLoadingListener onLoadingListener) {
+        if (swipeLayout != null)
+            swipeLayout.setOnLoadingListener(onLoadingListener);
+    }
+
+    public void finishPullRefresh() {
+        if (swipeLayout != null)
+            swipeLayout.finishPullRefresh();
+    }
+
+    public void finishPullLoad() {
+        if (swipeLayout != null)
+            swipeLayout.finishPullLoad();
+    }
+
+    /**
+     * Init wipelayout
+     */
+    private WXSwipeLayout createBounceView(Context context) {
+        swipeLayout = new WXSwipeLayout(context);
+        swipeLayout.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
+        mInnerView = setInnerView(context);
+        if (mInnerView == null)
+            return null;
+        swipeLayout.addTargetView(mInnerView);
+        addView(swipeLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        return swipeLayout;
+    }
+
+    /**
+     * @return the child of swipelayout : recyclerview or scrollview
+     */
+    public T getInnerView() {
+        return mInnerView;
+    }
+
+    public abstract T setInnerView(Context context);
+
+    /**
+     *
+     * @param refresh should be {@link WXRefreshView}
+     */
+    public void setHeaderView(WXComponent refresh) {
+        setRefreshEnable(true);
+        if (swipeLayout != null) {
+            WXRefreshView refreshView = swipeLayout.getHeaderView();
+            if (refreshView != null) {
+                if (refresh != null) {
+                    int refreshHeight = (int) refresh.getLayoutHeight();
+                    swipeLayout.setRefreshHeight(refreshHeight);
+                    String colorStr = (String) refresh.getStyles().get(Constants.Name.BACKGROUND_COLOR);
+                    String bgColor = WXUtils.getString(colorStr, null);
+                    if (bgColor != null) {
+                        if (!TextUtils.isEmpty(bgColor)) {
+                            int colorInt = WXResourceUtils.getColor(bgColor);
+                            if (!(colorInt == Color.TRANSPARENT)) {
+                                swipeLayout.setRefreshBgColor(colorInt);
+                            }
+                        }
+                    }
+                    refreshView.setRefreshView(refresh.getHostView());
+                }
+            }
+        }
+    }
+
+    /**
+     *
+     * @param loading should be {@link WXRefreshView}
+     */
+    public void setFooterView(WXComponent loading) {
+        setLoadmoreEnable(true);
+        if (swipeLayout != null) {
+            WXRefreshView refreshView = swipeLayout.getFooterView();
+            if (refreshView != null) {
+                if (loading != null) {
+                    int loadingHeight = (int) loading.getLayoutHeight();
+                    swipeLayout.setLoadingHeight(loadingHeight);
+                    String colorStr = (String) loading.getStyles().get(Constants.Name.BACKGROUND_COLOR);
+                    String bgColor = WXUtils.getString(colorStr, null);
+                    if (bgColor != null) {
+                        if (!TextUtils.isEmpty(bgColor)) {
+                            int colorInt = WXResourceUtils.getColor(bgColor);
+                            if (!(colorInt == Color.TRANSPARENT)) {
+                                swipeLayout.setLoadingBgColor(colorInt);
+                            }
+                        }
+                    }
+                    refreshView.setRefreshView(loading.getHostView());
+                }
+            }
+        }
+    }
+
+    public void removeFooterView(WXComponent loading){
+        setLoadmoreEnable(false);
+        if(swipeLayout!=null){
+            if(swipeLayout.getFooterView()!=null){
+                swipeLayout.setLoadingHeight(0);
+                swipeLayout.getFooterView().removeView(loading.getHostView());
+                swipeLayout.finishPullLoad();
+            }
+        }
+    }
+    //TODO There are bugs, will be more than a rolling height
+    public void removeHeaderView(WXComponent refresh){
+        setRefreshEnable(false);
+        if(swipeLayout!=null){
+            if(swipeLayout.getHeaderView()!=null){
+                swipeLayout.setRefreshHeight(0);
+                swipeLayout.getHeaderView().removeView(refresh.getHostView());
+                swipeLayout.finishPullRefresh();
+            }
+        }
+    }
+
+    public void setRefreshEnable(boolean enable) {
+        if (swipeLayout != null)
+            swipeLayout.setPullRefreshEnable(enable);
+    }
+
+    public void setLoadmoreEnable(boolean enable) {
+        if (swipeLayout != null)
+            swipeLayout.setPullLoadEnable(enable);
+    }
+
+    @Override
+    public void removeView(View view) {
+        if (view instanceof WXLoadingLayout) {
+            finishPullLoad();
+            setLoadmoreEnable(false);
+            if (swipeLayout != null) {
+                swipeLayout.removeView(swipeLayout.getFooterView());
+            }
+        } else if (view instanceof WXRefreshLayout) {
+            finishPullRefresh();
+            setRefreshEnable(false);
+            if (swipeLayout != null) {
+                swipeLayout.removeView(swipeLayout.getHeaderView());
+            }
+        } else {
+            super.removeView(view);
+        }
+    }
+
+    public WXSwipeLayout getSwipeLayout() {
+        return swipeLayout;
+    }
+
+    public abstract void onRefreshingComplete();
+
+    public abstract void onLoadmoreComplete();
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BounceRecyclerView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BounceRecyclerView.java
new file mode 100644
index 0000000..761cfb8
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BounceRecyclerView.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.refresh.wrapper;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.view.MotionEvent;
+
+import org.apache.weex.ui.component.list.ListComponentView;
+import org.apache.weex.ui.component.list.StickyHeaderHelper;
+import org.apache.weex.ui.component.list.WXCell;
+import org.apache.weex.ui.view.gesture.WXGesture;
+import org.apache.weex.ui.view.gesture.WXGestureObservable;
+import org.apache.weex.ui.view.listview.WXRecyclerView;
+import org.apache.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
+
+@SuppressLint("ViewConstructor")
+public class BounceRecyclerView extends BaseBounceView<WXRecyclerView> implements ListComponentView,WXGestureObservable {
+
+  public static final int DEFAULT_COLUMN_COUNT = 1;
+  public static final int DEFAULT_COLUMN_GAP = 1;
+  private RecyclerViewBaseAdapter adapter = null;
+  private WXGesture mGesture;
+  private int mLayoutType = WXRecyclerView.TYPE_LINEAR_LAYOUT;
+  private int mColumnCount = DEFAULT_COLUMN_COUNT;
+  private float mColumnGap = DEFAULT_COLUMN_GAP;
+  private StickyHeaderHelper mStickyHeaderHelper;
+
+  public BounceRecyclerView(Context context,int type,int columnCount,float columnGap,int orientation) {
+    super(context, orientation);
+    mLayoutType = type;
+    mColumnCount = columnCount;
+    mColumnGap = columnGap;
+    init(context);
+    mStickyHeaderHelper = new StickyHeaderHelper(this);
+  }
+
+  public BounceRecyclerView(Context context,int type,int orientation) {
+    this(context,type, DEFAULT_COLUMN_COUNT, DEFAULT_COLUMN_GAP,orientation);
+  }
+
+  public void setRecyclerViewBaseAdapter(RecyclerViewBaseAdapter adapter) {
+    this.adapter = adapter;
+    if (getInnerView() != null) {
+      getInnerView().setAdapter(adapter);
+    }
+  }
+
+  public RecyclerViewBaseAdapter getRecyclerViewBaseAdapter() {
+    return adapter;
+  }
+
+  @Override
+  public boolean dispatchTouchEvent(MotionEvent event) {
+    boolean result = super.dispatchTouchEvent(event);
+    if (mGesture != null) {
+      result |= mGesture.onTouch(this, event);
+    }
+    return result;
+  }
+
+  @Override
+  public WXRecyclerView setInnerView(Context context) {
+    WXRecyclerView wxRecyclerView = new WXRecyclerView(context);
+    wxRecyclerView.initView(context, mLayoutType,mColumnCount,mColumnGap,getOrientation());
+    return wxRecyclerView;
+  }
+
+  @Override
+  public void onRefreshingComplete() {
+    if (adapter != null) {
+      adapter.notifyDataSetChanged();
+    }
+  }
+
+  @Override
+  public void onLoadmoreComplete() {
+    if (adapter != null) {
+      adapter.notifyDataSetChanged();
+    }
+  }
+
+  /**
+   * @param component
+   */
+  public void notifyStickyShow(WXCell component) {
+    mStickyHeaderHelper.notifyStickyShow(component);
+  }
+
+  @Override
+  public void updateStickyView(int currentStickyPos) {
+    mStickyHeaderHelper.updateStickyView(currentStickyPos);
+  }
+
+  /**
+   *
+   * @param compToRemove
+   */
+  @Override
+  public void notifyStickyRemove(WXCell compToRemove) {
+    mStickyHeaderHelper.notifyStickyRemove(compToRemove);
+  }
+
+  public StickyHeaderHelper getStickyHeaderHelper() {
+    return mStickyHeaderHelper;
+  }
+
+  @Override
+  public void registerGestureListener(@Nullable WXGesture wxGesture) {
+    mGesture = wxGesture;
+    getInnerView().registerGestureListener(wxGesture);
+  }
+
+  @Override
+  public WXGesture getGestureListener() {
+    return mGesture;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BounceScrollerView.java b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BounceScrollerView.java
new file mode 100644
index 0000000..7a4b6f9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/ui/view/refresh/wrapper/BounceScrollerView.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.ui.view.refresh.wrapper;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+
+import org.apache.weex.ui.component.WXScroller;
+import org.apache.weex.ui.view.WXScrollView;
+
+@SuppressLint("ViewConstructor")
+public class BounceScrollerView extends BaseBounceView<WXScrollView> {
+
+    public BounceScrollerView(Context context, int orientation, WXScroller waScroller) {
+        super(context,orientation);
+        init(context);
+        if (getInnerView() != null)
+            getInnerView().setWAScroller(waScroller);
+    }
+
+    @Override
+    public WXScrollView setInnerView(Context context) {
+        return new WXScrollView(context);
+    }
+
+    @Override
+    public void onRefreshingComplete() {
+        //TODO update scroller dataset
+    }
+
+    @Override
+    public void onLoadmoreComplete() {
+        //TODO update scroller dataset
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/ATagUtil.java b/android/sdk/src/main/java/org/apache/weex/utils/ATagUtil.java
new file mode 100644
index 0000000..c7c133d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/ATagUtil.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.net.Uri;
+import android.view.View;
+
+import com.alibaba.fastjson.JSONArray;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.URIAdapter;
+
+public class ATagUtil {
+  public static void onClick(View widget, String instanceId, String url) {
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance == null) {
+      return;
+    }
+    String href = instance.rewriteUri(Uri.parse(url), URIAdapter.LINK).toString();
+    JSONArray array = new JSONArray();
+    array.add(href);
+    WXSDKManager.getInstance().getWXBridgeManager().
+        callModuleMethod(instanceId, "event", "openURL", array);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/BoxShadowUtil.java b/android/sdk/src/main/java/org/apache/weex/utils/BoxShadowUtil.java
new file mode 100644
index 0000000..96872c6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/BoxShadowUtil.java
@@ -0,0 +1,669 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.IntRange;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.common.WXThread;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by moxun on 2017/9/4.
+ * Utils for create shadow layer on view
+ * Requires Android 4.3 and higher
+ *
+ * @see <a href="https://www.w3schools.com/cssref/css3_pr_box-shadow.asp">CSS3 box-shadow Property</>
+ */
+
+public class BoxShadowUtil {
+  private static final String TAG = "BoxShadowUtil";
+  private static boolean sBoxShadowEnabled = true /*disable box-shadow temporary*/;
+
+  private static Pattern sColorPattern;
+
+  public static void setBoxShadowEnabled(boolean enabled) {
+    sBoxShadowEnabled = enabled;
+    WXLogUtils.w(TAG, "Switch box-shadow status: " + enabled);
+  }
+
+  public static boolean isBoxShadowEnabled() {
+    return sBoxShadowEnabled;
+  }
+
+  public static void setBoxShadow(final View target, String style, final float[] radii, int viewPort, final float quality) {
+    if (!sBoxShadowEnabled) {
+      WXLogUtils.w(TAG, "box-shadow was disabled by config");
+      return;
+    }
+
+    if (target == null) {
+      WXLogUtils.w(TAG, "Target view is null!");
+      return;
+    }
+
+    if (TextUtils.isEmpty(style) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+      target.getOverlay().clear();
+      WXLogUtils.d(TAG, "Remove all box-shadow");
+      return;
+    }
+
+    final BoxShadowOptions[] shadows = parseBoxShadows(style, viewPort);
+    if (shadows == null || shadows.length == 0) {
+      WXLogUtils.w(TAG, "Failed to parse box-shadow: " + style);
+      return;
+    }
+
+    final List<BoxShadowOptions> normalShadows = new ArrayList<>(), insetShadows = new ArrayList<>();
+    for (BoxShadowOptions shadow : shadows) {
+      if (shadow != null) {
+        if (shadow.isInset) {
+          insetShadows.add(0, shadow);
+        } else {
+          normalShadows.add(0, shadow);
+        }
+      }
+    }
+
+    if (radii != null) {
+      if (radii.length != 8) {
+        WXLogUtils.w(TAG, "Length of radii must be 8");
+      } else {
+        for (int i = 0; i < radii.length; i++) {
+          float realRadius = WXViewUtils.getRealSubPxByWidth(radii[i], viewPort);
+          radii[i] = realRadius;
+        }
+      }
+    }
+
+    target.post(WXThread.secure(new Runnable() {
+      @Override
+      public void run() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+          target.getOverlay().clear();
+          if (normalShadows.size() > 0) {
+            setNormalBoxShadow(target, normalShadows, quality, radii);
+          }
+
+          if (insetShadows.size() > 0) {
+            setInsetBoxShadow(target, insetShadows, quality, radii);
+          }
+        }
+      }
+    }));
+  }
+
+  private static void drawShadow(Canvas canvas, BoxShadowOptions options) {
+    RectF shadowRect = new RectF(
+        0f, 0f,
+        options.viewWidth + 2f * options.spread, options.viewHeight + 2f * options.spread
+    );
+
+    if (options.topLeft != null) {
+      shadowRect.offset(options.topLeft.x, options.topLeft.y);
+    }
+
+    float shadowDx = options.blur;
+    float shadowDy = options.blur;
+    if (options.hShadow > 0) {
+      shadowDx = shadowDx + 2f * options.hShadow;
+    }
+    if (options.vShadow > 0) {
+      shadowDy = shadowDy + 2f * options.vShadow;
+    }
+    shadowRect.offset(shadowDx, shadowDy);
+
+    Paint shadowPaint = new Paint();
+    shadowPaint.setAntiAlias(true);
+    shadowPaint.setColor(options.color);
+    shadowPaint.setStyle(Paint.Style.FILL);
+
+    if (options.blur > 0) {
+      shadowPaint.setMaskFilter(new BlurMaskFilter(options.blur, BlurMaskFilter.Blur.NORMAL));
+    }
+
+    Path shadowPath = new Path();
+    float[] shadowRadii = new float[8];
+    for (int i = 0; i < options.radii.length; i++) {
+      float contentRadius = options.radii[i];
+      if (contentRadius == 0f) {
+        shadowRadii[i] = 0f;
+      } else {
+        shadowRadii[i] = options.radii[i] + options.spread;
+      }
+    }
+    shadowPath.addRoundRect(shadowRect, shadowRadii, Path.Direction.CCW);
+    canvas.drawPath(shadowPath, shadowPaint);
+
+    if (false && WXEnvironment.isApkDebugable()) {
+      Paint paint = new Paint();
+      paint.setAntiAlias(true);
+      paint.setColor(Color.BLACK);
+      paint.setStyle(Paint.Style.STROKE);
+      canvas.drawRect(shadowRect, paint);
+    }
+  }
+
+  private static void setNormalBoxShadow(View target, List<BoxShadowOptions> options, float quality, float[] radii) {
+    int h = target.getHeight();
+    int w = target.getWidth();
+
+    ViewGroup.LayoutParams p = target.getLayoutParams();
+
+    if (h == 0 || w == 0) {
+      Log.w(TAG, "Target view is invisible, ignore set shadow.");
+      return;
+    }
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+      int maxWidth = 0, maxHeight = 0;
+      for (BoxShadowOptions option : options) {
+        option.viewWidth = w;
+        option.viewHeight = h;
+        option.radii = radii;
+
+        Rect rect = option.getTargetCanvasRect();
+        if (maxWidth < rect.width()) {
+          maxWidth = rect.width();
+        }
+
+        if (maxHeight < rect.height()) {
+          maxHeight = rect.height();
+        }
+      }
+
+      int canvasWidth = (int) (maxWidth * quality);
+      int canvasHeight = (int) (maxHeight * quality);
+      Bitmap output = Bitmap.createBitmap(canvasWidth, canvasHeight, Bitmap.Config.ARGB_4444);
+      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+        WXLogUtils.d(TAG, "Allocation memory for box-shadow: " + (output.getAllocationByteCount() / 1024) + " KB");
+      }
+      Canvas canvas = new Canvas(output);
+
+      if (false && WXEnvironment.isApkDebugable()) {
+        // Using for debug
+        Paint strokePaint = new Paint();
+        strokePaint.setColor(Color.BLACK);
+        strokePaint.setStrokeWidth(2);
+        strokePaint.setStyle(Paint.Style.STROKE);
+        canvas.drawRect(canvas.getClipBounds(), strokePaint);
+      }
+
+      for (BoxShadowOptions option : options) {
+        Rect rect = option.getTargetCanvasRect();
+        float left = (maxWidth - rect.width()) / 2f;
+        float top = (maxHeight - rect.height()) / 2f;
+        option.topLeft = new PointF(left, top);
+
+        BoxShadowOptions scaledOption = option.scale(quality);
+        drawShadow(canvas, scaledOption);
+      }
+
+      //Drawable's bounds must match the bitmap size, otherwise the shadows will be scaled
+      int paddingX = (maxWidth - w) / 2;
+      int paddingY = (maxHeight - h) / 2;
+      OverflowBitmapDrawable shadowDrawable = new OverflowBitmapDrawable(target.getResources(),
+          output, new Point(paddingX, paddingY), new Rect(0, 0, w, h), radii);
+
+      target.getOverlay().add(shadowDrawable);
+      //Relayout to ensure the shadows are fully drawn
+      ViewParent parent = target.getParent();
+      if (parent != null) {
+        parent.requestLayout();
+        if (parent instanceof ViewGroup) {
+          ((ViewGroup) parent).invalidate(shadowDrawable.getBounds());
+        }
+      }
+    } else {
+      // I have a dream that one day our minSdkVersion will equals or higher than 21
+      Log.w("BoxShadowUtil", "Call setNormalBoxShadow() requires API level 18 or higher.");
+    }
+  }
+
+  private static void setInsetBoxShadow(View target, List<BoxShadowOptions> options, float quality, float[] radii) {
+    if (target == null || options == null) {
+      WXLogUtils.w(TAG, "Illegal arguments");
+      return;
+    }
+
+    if (target.getWidth() == 0 || target.getHeight() == 0) {
+      WXLogUtils.w(TAG, "Target view is invisible, ignore set shadow.");
+      return;
+    }
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+      Drawable[] drawables = new Drawable[options.size()];
+      for (int i = 0; i < options.size(); i++) {
+        BoxShadowOptions option = options.get(i);
+        Drawable shadow = new InsetShadowDrawable(target.getWidth(), target.getHeight(),
+            option.hShadow, option.vShadow,
+            option.blur, option.spread,
+            option.color, radii);
+        drawables[i] = shadow;
+      }
+
+      LayerDrawable layerDrawable = new LayerDrawable(drawables);
+      target.getOverlay().add(layerDrawable);
+      target.invalidate();
+    } else {
+      Log.w(TAG, "Call setInsetBoxShadow() requires API level 18 or higher.");
+    }
+  }
+
+  public static BoxShadowOptions[] parseBoxShadows(String boxShadowStyle, int viewport) {
+    // normalization color expression to #AARRGGBB
+    if (sColorPattern == null) {
+      sColorPattern = Pattern.compile("([rR][gG][bB][aA]?)\\((\\d+\\s*),\\s*(\\d+\\s*),\\s*(\\d+\\s*)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)");
+    }
+
+    Matcher matcher = sColorPattern.matcher(boxShadowStyle);
+
+    String processedStyle = boxShadowStyle;
+    while (matcher.find()) {
+      String color = matcher.group();
+      processedStyle = processedStyle.replace(color, "#" + String.format("%8s", Integer.toHexString(WXResourceUtils.getColor(color, Color.BLACK))).replaceAll("\\s", "0"));
+    }
+
+    String[] styles = processedStyle.split(",");
+    if (styles != null && styles.length > 0) {
+      BoxShadowOptions[] result = new BoxShadowOptions[styles.length];
+      for (int i = 0; i < styles.length; i++) {
+        result[i] = parseBoxShadow(styles[i], viewport);
+      }
+      return result;
+    }
+    return null;
+  }
+
+  private static BoxShadowOptions parseBoxShadow(String boxShadow, int viewport) {
+    BoxShadowOptions result = new BoxShadowOptions(viewport);
+    if (TextUtils.isEmpty(boxShadow)) {
+      return null;
+    }
+
+    String boxShadowCopy = boxShadow;
+
+    // trim rgb() & rgba()
+    boxShadowCopy = boxShadowCopy.replaceAll("\\s*,\\s+", ",");
+
+    // match inset first
+    if (boxShadowCopy.contains("inset")) {
+      result.isInset = true;
+      boxShadowCopy = boxShadowCopy.replace("inset", "");
+    }
+
+    boxShadowCopy = boxShadowCopy.trim();
+    List<String> params = new ArrayList<>(Arrays.asList(boxShadowCopy.split("\\s+")));
+
+    // match color
+    String maybeColor = params.get(params.size() - 1);
+    if (!TextUtils.isEmpty(maybeColor)) {
+      if (maybeColor.startsWith("#") || maybeColor.startsWith("rgb") || WXResourceUtils.isNamedColor(maybeColor)) {
+        result.color = WXResourceUtils.getColor(maybeColor, Color.BLACK);
+        params.remove(params.size() - 1);
+      }
+    }
+
+    try {
+      if (params.size() < 2) {
+        // Missing required param
+        return null;
+      } else {
+        if (!TextUtils.isEmpty(params.get(0))) {
+          float px = WXUtils.getFloat(params.get(0).trim(), 0f);
+          result.hShadow = WXViewUtils.getRealSubPxByWidth(px, viewport);
+        }
+
+        if (!TextUtils.isEmpty(params.get(1))) {
+          float px = WXUtils.getFloat(params.get(1).trim(), 0f);
+          result.vShadow = WXViewUtils.getRealPxByWidth(px, viewport);
+        }
+
+        for (int i = 2; i < params.size(); i++) {
+          int parserIndex = i - 2;
+          BoxShadowOptions.IParser parser = result.optionParamParsers.get(parserIndex);
+          parser.parse(params.get(i));
+        }
+      }
+    } catch (Throwable t) {
+      t.printStackTrace();
+    }
+    return result;
+  }
+
+  private static class OverflowBitmapDrawable extends BitmapDrawable {
+    private int paddingX;
+    private int paddingY;
+    private Rect viewRect;
+    private float[] radii;
+
+    private OverflowBitmapDrawable(Resources resources, Bitmap bitmap, Point topLeft, Rect viewRect, float[] radii) {
+      super(resources, bitmap);
+      this.paddingX = topLeft.x;
+      this.paddingY = topLeft.y;
+      this.viewRect = viewRect;
+      this.radii = radii;
+
+      setBounds(-paddingX, -paddingY, viewRect.width() + paddingX, viewRect.height() + paddingY);
+    }
+
+    public void draw(Canvas canvas) {
+      Rect bounds = canvas.getClipBounds();
+      Rect newRect = new Rect(bounds);
+      // Make the Canvas Rect bigger according to the padding.
+      newRect.inset(-paddingX * 2, -paddingY * 2);
+      try {
+        if(WXEnvironment.sApplication.getApplicationInfo().targetSdkVersion > VERSION_CODES.O){
+          canvas.clipRect(newRect);
+        }
+        else{
+          canvas.clipRect(newRect, Region.Op.REPLACE);
+        }
+      }catch (NullPointerException e) {
+        canvas.clipRect(newRect);
+      }
+
+      Path contentPath = new Path();
+      // the content area map must be aligned with bounds
+      RectF rectF = new RectF(bounds);
+      contentPath.addRoundRect(rectF, radii, Path.Direction.CCW);
+      // can not antialias
+      canvas.clipPath(contentPath, Region.Op.DIFFERENCE);
+
+      // translate the canvas to a suitable position and then draw the bitmap, otherwise draw from the origin(0, 0)
+      canvas.translate(bounds.left, bounds.top);
+
+      super.draw(canvas);
+    }
+  }
+
+  private static class InsetShadowDrawable extends Drawable {
+    private static final int LEFT_TO_RIGHT = 0;
+    private static final int TOP_TO_BOTTOM = 1;
+    private static final int RIGHT_TO_LEFT = 2;
+    private static final int BOTTOM_TO_TOP = 3;
+
+    private float blurRadius;
+    private int shadowColor;
+
+    private float[] radii;
+
+    private float width, height;
+
+    private float shadowXSize, shadowYSize;
+
+    private Shader[] shades = new Shader[4];
+    private Path[] paths = new Path[4];
+
+    private Paint paint;
+
+    private InsetShadowDrawable(int viewWidth, int viewHeight, float dx, float dy, float blurRadius, float spread, int shadowColor, float[] radii) {
+      this.blurRadius = blurRadius;
+      this.shadowColor = shadowColor;
+
+      this.width = viewWidth + 2 * dx;
+      this.height = viewHeight + 2 * dy;
+
+      this.shadowXSize = dx + spread;
+      this.shadowYSize = dy + spread;
+
+      this.radii = radii;
+
+      setBounds(0, 0, viewWidth, viewHeight);
+      prepare();
+    }
+
+    private void prepare() {
+      /*
+       *  A +++++++++++++++++++++++++ B
+       *  +  E ------------------- F  +
+       *  +  |                     |  +
+       *  +  |                     |  +
+       *  +  |                     |  +
+       *  +  H ------------------- G  +
+       *  D +++++++++++++++++++++++++ C
+       */
+
+      PointF a = new PointF(0, 0);
+      PointF b = new PointF(width, 0);
+      PointF c = new PointF(b.x, height);
+      PointF d = new PointF(a.x, c.y);
+
+      PointF e = new PointF(shadowXSize, shadowYSize);
+      PointF f = new PointF(b.x - shadowXSize, e.y);
+      PointF g = new PointF(f.x, c.y - shadowYSize);
+      PointF h = new PointF(e.x, g.y);
+
+      Shader ltr = new LinearGradient(e.x - blurRadius, e.y, e.x, e.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
+      Shader ttb = new LinearGradient(e.x, e.y - blurRadius, e.x, e.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
+      Shader rtl = new LinearGradient(g.x + blurRadius, g.y, g.x, g.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
+      Shader btt = new LinearGradient(g.x, g.y + blurRadius, g.x, g.y, shadowColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
+
+      shades[LEFT_TO_RIGHT] = ltr;
+      shades[TOP_TO_BOTTOM] = ttb;
+      shades[RIGHT_TO_LEFT] = rtl;
+      shades[BOTTOM_TO_TOP] = btt;
+
+      Path ltrPath = new Path();
+      ltrPath.moveTo(a.x, a.y);
+      ltrPath.lineTo(e.x, e.y);
+      ltrPath.lineTo(h.x, h.y);
+      ltrPath.lineTo(d.x, d.y);
+      ltrPath.close();
+
+      Path ttbPath = new Path();
+      ttbPath.moveTo(a.x, a.y);
+      ttbPath.lineTo(b.x, b.y);
+      ttbPath.lineTo(f.x, f.y);
+      ttbPath.lineTo(e.x, e.y);
+      ttbPath.close();
+
+      Path rtlPath = new Path();
+      rtlPath.moveTo(b.x, b.y);
+      rtlPath.lineTo(c.x, c.y);
+      rtlPath.lineTo(g.x, g.y);
+      rtlPath.lineTo(f.x, f.y);
+      rtlPath.close();
+
+      Path bttPath = new Path();
+      bttPath.moveTo(d.x, d.y);
+      bttPath.lineTo(c.x, c.y);
+      bttPath.lineTo(g.x, g.y);
+      bttPath.lineTo(h.x, h.y);
+      bttPath.close();
+
+      paths[LEFT_TO_RIGHT] = ltrPath;
+      paths[TOP_TO_BOTTOM] = ttbPath;
+      paths[RIGHT_TO_LEFT] = rtlPath;
+      paths[BOTTOM_TO_TOP] = bttPath;
+
+      paint = new Paint();
+      paint.setAntiAlias(true);
+      paint.setStyle(Paint.Style.FILL);
+      paint.setColor(shadowColor);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+      Rect bounds = canvas.getClipBounds();
+      Path border = new Path();
+      RectF rectF = new RectF(bounds);
+      border.addRoundRect(rectF, radii, Path.Direction.CCW);
+      canvas.clipPath(border);
+      //TODO: we need clip border-width too
+
+      // translate the canvas to the right place and then draw the inner shadow
+      canvas.translate(bounds.left, bounds.top);
+
+      for (int i = 0; i < 4; i++) {
+        Shader shader = shades[i];
+        Path path = paths[i];
+        paint.setShader(shader);
+        canvas.drawPath(path, paint);
+      }
+    }
+
+    @Override
+    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
+
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+
+    }
+
+    @Override
+    public int getOpacity() {
+      return PixelFormat.OPAQUE;
+    }
+  }
+
+  public static class BoxShadowOptions {
+    private List<IParser> optionParamParsers;
+    private int viewport = 750;
+
+    public float hShadow;
+    public float vShadow;
+    public float blur = 0f;
+    public float spread = 0f;
+    public float[] radii = new float[]{0, 0, 0, 0, 0, 0, 0, 0};
+    public int color = Color.BLACK;
+    public boolean isInset = false;
+
+    public int viewWidth = 0;
+    public int viewHeight = 0;
+    public PointF topLeft = null;
+
+    private BoxShadowOptions(int vp) {
+      if (viewport != 0) {
+        this.viewport = vp;
+      }
+      optionParamParsers = new ArrayList<>();
+
+      IParser spreadParser = new IParser() {
+        @Override
+        public void parse(String param) {
+          if (!TextUtils.isEmpty(param)) {
+            float px = WXUtils.getFloat(param, 0f);
+            spread = WXViewUtils.getRealSubPxByWidth(px, viewport);
+            WXLogUtils.w(TAG, "Experimental box-shadow attribute: spread");
+          }
+        }
+      };
+
+      IParser blurParser = new IParser() {
+        @Override
+        public void parse(String param) {
+          if (!TextUtils.isEmpty(param)) {
+            float px = WXUtils.getFloat(param, 0f);
+            blur = WXViewUtils.getRealSubPxByWidth(px, viewport);
+          }
+        }
+      };
+
+      optionParamParsers.add(blurParser);
+      optionParamParsers.add(spreadParser);
+    }
+
+    public BoxShadowOptions scale(float scale) {
+      if (scale > 0f && scale <= 1f) {
+        BoxShadowOptions scaledOptions = new BoxShadowOptions(viewport);
+        scaledOptions.hShadow = hShadow * scale;
+        scaledOptions.vShadow = vShadow * scale;
+        scaledOptions.blur = blur * scale;
+        scaledOptions.spread = spread * scale;
+        for (int i = 0; i < radii.length ; i++) {
+          scaledOptions.radii[i] = radii[i] * scale;
+        }
+        scaledOptions.viewHeight = (int) (viewHeight * scale);
+        scaledOptions.viewWidth = (int) (viewWidth * scale);
+
+        if (topLeft != null) {
+          scaledOptions.topLeft = new PointF();
+          scaledOptions.topLeft.x = topLeft.x * scale;
+          scaledOptions.topLeft.y = topLeft.y * scale;
+        }
+
+        scaledOptions.color = color;
+        scaledOptions.isInset = isInset;
+        WXLogUtils.d(TAG, "Scaled BoxShadowOptions: [" + scale + "] " + scaledOptions);
+        return scaledOptions;
+      }
+      return null;
+    }
+
+    public Rect getTargetCanvasRect() {
+      int canvasWidth = viewWidth + 2 * (int) (blur + spread + Math.abs(hShadow));
+      int canvasHeight = viewHeight + 2 * (int) (blur + spread + Math.abs(vShadow));
+      return new Rect(0, 0, canvasWidth, canvasHeight);
+    }
+
+    @Override
+    public String toString() {
+
+      String r = "[" + radii[0] + "," + radii[2] + "," + radii[4] + "," + radii[6] + "]";
+
+      final StringBuffer sb = new StringBuffer("BoxShadowOptions{");
+      sb.append("h-shadow=").append(hShadow);
+      sb.append(", v-shadow=").append(vShadow);
+      sb.append(", blur=").append(blur);
+      sb.append(", spread=").append(spread);
+      sb.append(", corner-radius=").append(r);
+      sb.append(", color=#").append(Integer.toHexString(color));
+      sb.append(", inset=").append(isInset);
+      sb.append('}');
+      return sb.toString();
+    }
+
+    private interface IParser {
+      void parse(String param);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/FontDO.java b/android/sdk/src/main/java/org/apache/weex/utils/FontDO.java
new file mode 100644
index 0000000..2e91459
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/FontDO.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Base64;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.adapter.URIAdapter;
+import org.apache.weex.common.Constants;
+import java.io.File;
+
+public class FontDO {
+  private final String mFontFamilyName;
+  private String mUrl = "";
+  private String mFilePath;
+  private int mType = TYPE_NETWORK;
+  private Typeface mTypeface;
+  private int mState = STATE_INVALID;
+
+  public final static int STATE_INVALID = -1;
+  public final static int STATE_INIT = 0;
+  public final static int STATE_LOADING = 1;
+  public final static int STATE_SUCCESS = 2;
+  public final static int STATE_FAILED = 3;
+
+  public final static int TYPE_UNKNOWN = 0;
+  public final static int TYPE_NETWORK = 1;
+  public final static int TYPE_FILE = 2;
+  public final static int TYPE_LOCAL = 3;
+  public final static int TYPE_NATIVE = 4;
+  public final static int TYPE_BASE64 = 5;
+
+
+  public FontDO (String fontFamilyName, String src, WXSDKInstance instance) {
+    this.mFontFamilyName = fontFamilyName;
+    parseSrc(src,instance);
+  }
+
+  public FontDO (String fontFamilyName, Typeface typeface) {
+    this.mFontFamilyName = fontFamilyName;
+    this.mTypeface = typeface;
+    this.mType = TYPE_NATIVE;
+    this.mState = STATE_SUCCESS;
+  }
+
+  public String getFontFamilyName() {
+    return mFontFamilyName;
+  }
+
+  private void parseSrc(String src, WXSDKInstance instance) {
+    src = (src != null )? src.trim() : "";
+
+    if (instance != null) {
+      if (instance.getCustomFontNetworkHandler() != null) {
+        String localUrl = instance.getCustomFontNetworkHandler().fetchLocal(src);
+        if (!TextUtils.isEmpty(localUrl)) {
+          src = localUrl;
+        }
+      }
+    }
+
+    if (src.isEmpty()) {
+      mState = STATE_INVALID;
+      WXLogUtils.e("TypefaceUtil", "font src is empty.");
+      return;
+    }
+
+    if (src.matches("^url\\((('.*')|(\".*\"))\\)$")) {
+      String url = src.substring(5, src.length() - 2);
+      Uri uri = Uri.parse(url);
+      if( instance != null){
+        uri = instance.rewriteUri(uri, URIAdapter.FONT);
+      }
+      mUrl = uri.toString();
+      try {
+        String scheme = uri.getScheme();
+        if (Constants.Scheme.HTTP.equals(scheme) ||
+                Constants.Scheme.HTTPS.equals(scheme)) {
+          mType = TYPE_NETWORK;
+        } else if (Constants.Scheme.FILE.equals(scheme)) {
+          mType = TYPE_FILE;
+            /**
+             * eg: file://name/A/B.ttf
+             * getPath() = "A/B.ttf",but the real absolute path is "/name/A/B.ttf"
+             * so use getEncodedSchemeSpecificPart() to replaced = "//name/A/B.ttf"
+             */
+            mUrl = uri.getEncodedSchemeSpecificPart();
+        } else if (Constants.Scheme.LOCAL.equals(scheme)){
+          mType = TYPE_LOCAL;
+        } else if (Constants.Scheme.DATA.equals(scheme)) {
+          long start = System.currentTimeMillis();
+          String[] data = mUrl.split(",");
+          if (data != null && data.length == 2) {
+            String identify = data[0];
+            if (!TextUtils.isEmpty(identify) && identify.endsWith("base64")) {
+              //Do not check mime type and charset for now
+              String base64Data = data[1];
+              if (!TextUtils.isEmpty(base64Data)) {
+                String md5 = WXFileUtils.md5(base64Data);
+                File cacheDir = new File(WXEnvironment.getApplication().getCacheDir(),
+                    "font-family");
+                if (!cacheDir.exists()) {
+                  cacheDir.mkdirs();
+                }
+                File tmpFile = new File(cacheDir, md5);
+                if(!tmpFile.exists()){
+                  tmpFile.createNewFile();
+                  WXFileUtils.saveFile(tmpFile.getPath(), Base64.decode(base64Data, Base64.DEFAULT), WXEnvironment.getApplication());
+                }
+                mUrl = tmpFile.getPath();
+                mType = TYPE_BASE64;
+                WXLogUtils.d("TypefaceUtil", "Parse base64 font cost " + (System.currentTimeMillis() - start) + " ms");
+              }
+            }
+          }
+        } else {
+          WXLogUtils.e("TypefaceUtil", "Unknown scheme for font url: " + mUrl);
+          mType = TYPE_UNKNOWN;
+        }
+        mState = STATE_INIT;
+      } catch (Exception e) {
+        mType = STATE_INVALID;
+        WXLogUtils.e("TypefaceUtil", "URI.create(mUrl) failed mUrl: " + mUrl+ "\n"+ WXLogUtils.getStackTrace(e));
+      }
+    } else {
+      mUrl = src;
+      mState = STATE_INVALID;
+    }
+
+    if(WXEnvironment.isApkDebugable()) {
+      WXLogUtils.d("TypefaceUtil", "src:" + src + ", mUrl:" + mUrl + ", mType:" + mType);
+    }
+  }
+
+  public String getUrl() {
+    return mUrl;
+  }
+
+  public int getType() {
+    return mType;
+  }
+
+  public Typeface getTypeface() {
+    return mTypeface;
+  }
+
+  public void setTypeface(Typeface typeface) {
+    this.mTypeface = typeface;
+  }
+
+  public int getState() {
+    return mState;
+  }
+
+  public void setState(int state) {
+    this.mState = state;
+  }
+
+  public String getFilePath() {
+    return mFilePath;
+  }
+
+  public void setFilePath(String mFilePath) {
+    this.mFilePath = mFilePath;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/FunctionParser.java b/android/sdk/src/main/java/org/apache/weex/utils/FunctionParser.java
new file mode 100644
index 0000000..72953cd
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/FunctionParser.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.support.annotation.NonNull;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Parser for function like "rotate(30 ) transform(50 , 20)".
+ * This class will translate the raw string presentation of a group of function(s) to give type
+ * according to the {@link FunctionParser.Mapper}
+ */
+public class FunctionParser<K, V> {
+
+  public static final char SPACE = ' ';
+
+  private Mapper<K, V> mapper;
+  private Lexer lexer;
+
+  /**
+   * Construct a function parser
+   * @param source the raw string representation of a group of function(s)
+   * @param mapper the mapping rule between string and corresponding type of object.
+   */
+  public FunctionParser(@NonNull String source, @NonNull Mapper<K, V> mapper) {
+    this.lexer = new Lexer(source);
+    this.mapper = mapper;
+  }
+
+  /**
+   * Start to parse the raw string. The result will be stored in a sorted map where the order
+   * is defined by the function order in the raw string.
+   * @return
+   */
+  public LinkedHashMap<K, V> parse() {
+    lexer.moveOn();
+    return definition();
+  }
+
+  private LinkedHashMap<K, V> definition() {
+    LinkedHashMap<K, V> result = new LinkedHashMap<>();
+    do {
+      result.putAll(function());
+    } while (lexer.getCurrentToken() == Token.FUNC_NAME);
+    return result;
+  }
+
+  private Map<K, V> function() {
+    List<String> list = new LinkedList<>();
+    String functionName = match(Token.FUNC_NAME);
+    match(Token.LEFT_PARENT);
+    list.add(match(Token.PARAM_VALUE));
+    while (lexer.getCurrentToken() == Token.COMMA) {
+      match(Token.COMMA);
+      list.add(match(Token.PARAM_VALUE));
+    }
+    match(Token.RIGHT_PARENT);
+    return mapper.map(functionName, list);
+  }
+
+  private String match(Token token) {
+    try {
+      if (token == lexer.getCurrentToken()) {
+        String value = lexer.getCurrentTokenValue();
+        lexer.moveOn();
+        return value;
+      }
+    } catch (Exception e) {
+      WXLogUtils.e(token + "Token doesn't match" + lexer.source);
+    }
+    return "";
+  }
+
+  private enum Token {
+    FUNC_NAME, PARAM_VALUE, LEFT_PARENT, RIGHT_PARENT, COMMA
+  }
+
+  public interface Mapper<K, V> {
+
+    /**
+     * Map one function to a specified type of object
+     * @param functionName the name of the raw function.
+     * @param raw the list of parameter of the raw function
+     * @return the expected mapping relationship, where the key in the map is the same as the
+     * key in the return value of {{@link #parse()}},
+     * and the value in the map is the type of object that expected by user.
+     */
+    Map<K, V> map(String functionName, List<String> raw);
+  }
+
+  private static class WXInterpretationException extends RuntimeException {
+
+    private WXInterpretationException(String msg) {
+      super(msg);
+    }
+  }
+
+  /**
+   * Lexer for the parser. For now,  digit, alphabet, '(', ')', '.', ',', '+', '-' and '%' is
+   * valid character, and '(', ')', ',', parameter value and function name is valid token.
+   * Parameter value is defined as "(?i)[\+-]?[0-9]+(\.[0-9]+)?(%||deg||px)?" while function
+   * name is defined as "[a-zA-Z]+".
+   *
+   * The Lexer can also be expressed using the following EBNF format.
+   * <ul>
+   *   <li>definition = {function};</li>
+   *   <li>function = name, "(", value, { ",", value } , ")";</li>
+   *   <li>name = character, {character};</li>
+   *   <li>value = identifier, {identifier};</li>
+   *   <li>identifier = character | "." | "%" | "+" | "-";</li>
+   *   <li>character = digit | letter;</li>
+   *   <li>digit =  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;</li>
+   *   <li>letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" |
+   *   "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" |
+   *   "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" |
+   *   "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" ;</li>
+   * </ul>
+   */
+  private static class Lexer {
+
+    private static final String LEFT_PARENT = "(";
+    private static final String RIGHT_PARENT = ")";
+    private static final String COMMA = ",";
+    private static final char A_LOWER = 'a';
+    private static final char Z_LOWER = 'z';
+    private static final char A_UPPER = 'A';
+    private static final char Z_UPPER = 'Z';
+    private static final char ZERO = '0';
+    private static final char NINE = '9';
+    private static final char DOT = '.';
+    private static final char MINUS = '-';
+    private static final char PLUS = '+';
+    private String source;
+    private Token current;
+    private String value;
+    private int pointer = 0;
+
+    private Lexer(String source) {
+      this.source = source;
+    }
+
+    private Token getCurrentToken() {
+      return current;
+    }
+
+    private String getCurrentTokenValue() {
+      return value;
+    }
+
+    private boolean moveOn() {
+      int start = pointer;
+      char curChar;
+      while (pointer < source.length()) {
+        curChar = source.charAt(pointer);
+        if (curChar == SPACE) {
+          if (start == pointer++) {
+            start++;
+          } else {
+            break;
+          }
+        } else if (isCharacterOrDigit(curChar) || curChar == DOT
+                || curChar == WXUtils.PERCENT || curChar == MINUS || curChar == PLUS) {
+          pointer++;
+        } else {
+          if (start == pointer) {
+            pointer++;
+          }
+          break;
+        }
+      }
+      if (start != pointer) {
+        String symbol = source.substring(start, pointer);
+        moveOn(symbol);
+        return true;
+      } else {
+        current = null;
+        value = null;
+        return false;
+      }
+    }
+
+    private void moveOn(String token) {
+      if (LEFT_PARENT.equals(token)) {
+        current = Token.LEFT_PARENT;
+        value = LEFT_PARENT;
+      } else if (RIGHT_PARENT.equals(token)) {
+        current = Token.RIGHT_PARENT;
+        value = RIGHT_PARENT;
+      } else if (COMMA.equals(token)) {
+        current = Token.COMMA;
+        value = COMMA;
+      } else if (isFuncName(token)) {
+        current = Token.FUNC_NAME;
+        value = token;
+      } else {
+        current = Token.PARAM_VALUE;
+        value = token;
+      }
+    }
+
+    private boolean isFuncName(CharSequence funcName) {
+      char letter;
+      for (int i = 0; i < funcName.length(); i++) {
+        letter = funcName.charAt(i);
+        if (!((A_LOWER <= letter && letter <= Z_LOWER) ||
+                (A_UPPER <= letter && letter <= Z_UPPER) ||
+                letter == MINUS)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    private boolean isCharacterOrDigit(char letter) {
+      return (ZERO <= letter && letter <= NINE) || (A_LOWER <= letter && letter <= Z_LOWER) ||
+              (A_UPPER <= letter && letter <= Z_UPPER);
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/ImageDrawable.java b/android/sdk/src/main/java/org/apache/weex/utils/ImageDrawable.java
new file mode 100644
index 0000000..6714a39
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/ImageDrawable.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
+import android.graphics.drawable.shapes.Shape;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.widget.ImageView;
+
+public class ImageDrawable extends PaintDrawable {
+
+  public static Drawable createImageDrawable(@Nullable Drawable original,
+                                             @NonNull ImageView.ScaleType scaleType,
+                                             @Nullable float[] borderRadius,
+                                             int vWidth,
+                                             int vHeight,
+                                             boolean gif) {
+    Bitmap bm;
+    if (!gif && vWidth > 0 && vHeight > 0) {
+      if (original instanceof BitmapDrawable &&
+              (bm = ((BitmapDrawable) original).getBitmap()) != null) {
+        ImageDrawable imageDrawable;
+        imageDrawable = new ImageDrawable();
+        // fix android 9 image antialiasing
+        imageDrawable.getPaint().setFilterBitmap(true);
+        imageDrawable.bitmapWidth = bm.getWidth();
+        imageDrawable.bitmapHeight = bm.getHeight();
+        BitmapShader bitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+        updateShaderAndSize(scaleType, vWidth, vHeight, imageDrawable, bitmapShader);
+        imageDrawable.getPaint().setShader(bitmapShader);
+        return imageDrawable;
+      } else if (original instanceof ImageDrawable) {
+        ImageDrawable imageDrawable = (ImageDrawable) original;
+        if (imageDrawable.getPaint() != null &&
+                imageDrawable.getPaint().getShader() instanceof BitmapShader) {
+          BitmapShader bitmapShader = (BitmapShader) imageDrawable.getPaint().getShader();
+          updateShaderAndSize(scaleType, vWidth, vHeight, imageDrawable, bitmapShader);
+          return imageDrawable;
+        }
+      }
+    }
+    return original;
+  }
+
+  private static void updateShaderAndSize(@NonNull ImageView.ScaleType scaleType, int vWidth, int vHeight, ImageDrawable imageDrawable, BitmapShader bitmapShader) {
+    Matrix matrix = createShaderMatrix(scaleType, vWidth, vHeight,
+            imageDrawable.bitmapWidth,
+            imageDrawable.bitmapHeight);
+    int intrinsicWidth = vWidth, intrinsicHeight = vHeight;
+    if (scaleType == ImageView.ScaleType.FIT_CENTER) {
+      RectF bitmapRect = new RectF(0, 0, imageDrawable.bitmapWidth, imageDrawable.bitmapHeight), contentRect = new RectF();
+      matrix.mapRect(contentRect, bitmapRect);
+      intrinsicWidth = (int) contentRect.width();
+      intrinsicHeight = (int) contentRect.height();
+      matrix = createShaderMatrix(scaleType, intrinsicWidth, intrinsicHeight, imageDrawable
+              .bitmapWidth, imageDrawable.bitmapHeight);
+    }
+    imageDrawable.setIntrinsicWidth(intrinsicWidth);
+    imageDrawable.setIntrinsicHeight(intrinsicHeight);
+    bitmapShader.setLocalMatrix(matrix);
+  }
+
+  @NonNull
+  private static Matrix createShaderMatrix(@NonNull ImageView.ScaleType scaleType, int vWidth,
+                                           int vHeight, int bmWidth, int bmHeight) {
+    float scale, translateX = 0, translateY = 0;
+
+    if (bmWidth * vHeight > bmHeight * vWidth) {
+      scale = vHeight / (float) bmHeight;
+      translateX = (vWidth - bmWidth * scale) * 0.5f;
+    } else {
+      scale = vWidth / (float) bmWidth;
+      translateY = (vHeight - bmHeight * scale) * 0.5f;
+    }
+
+    Matrix mMatrix = new Matrix();
+    if (scaleType == ImageView.ScaleType.FIT_XY) {
+      mMatrix.setScale(vWidth / (float) bmWidth, vHeight / (float) bmHeight);
+    } else if (scaleType == ImageView.ScaleType.FIT_CENTER) {
+      RectF src = new RectF(0, 0, bmWidth, bmHeight);
+      RectF dist = new RectF(0, 0, vWidth, vHeight);
+      mMatrix.setRectToRect(src, dist, Matrix.ScaleToFit.CENTER);
+    } else if (scaleType == ImageView.ScaleType.CENTER_CROP) {
+      mMatrix.setScale(scale, scale);
+      mMatrix.postTranslate(translateX + 0.5f, translateY + 0.5f);
+    }
+    return mMatrix;
+  }
+
+  private float[] radii;
+  private int bitmapHeight;
+  private int bitmapWidth;
+
+  private ImageDrawable() {
+
+  }
+
+  @Override
+  public void setCornerRadii(float[] radii) {
+    this.radii = radii;
+    super.setCornerRadii(radii);
+  }
+
+  @Override
+  protected void onDraw(Shape shape, Canvas canvas, Paint paint) {
+    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
+      // fix api 21 PaintDrawable crash
+      paint.setAntiAlias(false);
+    }
+    super.onDraw(shape, canvas, paint);
+  }
+
+  public
+  @Nullable
+  float[] getCornerRadii() {
+    return this.radii;
+  }
+
+  public int getBitmapHeight() {
+    return bitmapHeight;
+  }
+
+  public int getBitmapWidth() {
+    return bitmapWidth;
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/ImgURIUtil.java b/android/sdk/src/main/java/org/apache/weex/utils/ImgURIUtil.java
new file mode 100644
index 0000000..15f56d4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/ImgURIUtil.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.support.v4.content.res.ResourcesCompat;
+
+import java.util.List;
+
+public class ImgURIUtil {
+
+  public static Drawable getDrawableFromLoaclSrc(Context context, Uri rewrited) {
+    Resources resources = context.getResources();
+    List<String> segments = rewrited.getPathSegments();
+    if (segments.size() != 1) {
+      WXLogUtils.e("Local src format is invalid.");
+      return null;
+    }
+    int id = resources.getIdentifier(segments.get(0), "drawable", context.getPackageName());
+    return id == 0 ? null : ResourcesCompat.getDrawable(resources, id, null);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/LogLevel.java b/android/sdk/src/main/java/org/apache/weex/utils/LogLevel.java
new file mode 100644
index 0000000..9279a65
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/LogLevel.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.util.Log;
+
+/**
+ * Created by lixinke on 16/5/11.
+ */
+public enum LogLevel {
+  OFF("off",8, Log.ASSERT),
+  WTF("wtf", 7, Log.ASSERT),
+  TLOG("tlog",6,Log.ERROR), //Add For Son Process
+  ERROR("error", 5, Log.ERROR),
+  WARN("warn", 4, Log.WARN),
+  INFO("info", 3, Log.INFO),
+  DEBUG("debug", 2, Log.DEBUG),
+  VERBOSE("verbose", 1, Log.VERBOSE),
+  ALL("all", 0, Log.VERBOSE),;
+  String name;
+  int value;
+  int priority;
+
+  LogLevel(String name, int value,int priority) {
+    this.name = name;
+    this.value = value;
+    this.priority = priority;
+  }
+  public String getName(){
+    return name;
+  }
+  public int getValue(){
+    return value;
+  }
+  public int getPriority(){
+    return priority;
+  }
+  public int compare(LogLevel level){
+    return value-level.value;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/OsVersion.java b/android/sdk/src/main/java/org/apache/weex/utils/OsVersion.java
new file mode 100644
index 0000000..9f39f31
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/OsVersion.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+/**
+ * Android OS version utilities.
+ */
+public class OsVersion {
+  private static boolean sIsAtLeastJB_MR2;
+
+
+  static {
+    final int v = getApiVersion();
+    sIsAtLeastJB_MR2 = v >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
+  }
+
+  /**
+   * @return True if the version of Android that we're running on is at
+   * least Jelly Bean MR2(API level 18).
+   */
+  public static boolean isAtLeastJB_MR2() {
+    return sIsAtLeastJB_MR2;
+  }
+
+  /**
+   * @return The Android API version of the running OS.
+   */
+  public static int getApiVersion() {
+    return android.os.Build.VERSION.SDK_INT;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/SingleFunctionParser.java b/android/sdk/src/main/java/org/apache/weex/utils/SingleFunctionParser.java
new file mode 100644
index 0000000..ac0f771
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/SingleFunctionParser.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.support.annotation.NonNull;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class SingleFunctionParser<V> extends FunctionParser<String, List<V>> {
+
+  public interface FlatMapper<V> {
+
+    V map(String raw);
+  }
+
+  public interface NonUniformMapper<V>{
+    List<V> map(List<String> raw);
+  }
+
+  /**
+   * Construct a function parser for uniform parameters.
+   * @param source the raw string representation of a group of function(s)
+   * @param mapper the mapping rule between string and corresponding type of object.
+   */
+  public SingleFunctionParser(@NonNull String source, @NonNull final FlatMapper<V> mapper) {
+    super(source, new Mapper<String, List<V>>() {
+      @Override
+      public Map<String, List<V>> map(String functionName, List<String> raw) {
+        Map<String, List<V>> map = new HashMap<String, List<V>>();
+        List<V> list = new LinkedList<V>();
+        for (String item : raw) {
+          list.add(mapper.map(item));
+        }
+        map.put(functionName, list);
+        return map;
+      }
+    });
+  }
+
+  /**
+   * Construct a function parser for non-uniform parameters.
+   * @param source the raw string representation of a group of function(s)
+   * @param mapper the mapping rule between string and corresponding type of object.
+   */
+  public SingleFunctionParser(@NonNull String source, @NonNull final NonUniformMapper<V> mapper) {
+    super(source, new Mapper<String, List<V>>() {
+      @Override
+      public Map<String, List<V>> map(String functionName, List<String> raw) {
+        Map<String, List<V>> map = new HashMap<String, List<V>>();
+        map.put(functionName, mapper.map(raw));
+        return map;
+      }
+    });
+  }
+
+  public List<V> parse(String functionName) {
+    Map<String, List<V>> map = parse();
+    if(map.containsKey(functionName)){
+      return map.get(functionName);
+    }
+    return null;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/StaticLayoutProxy.java b/android/sdk/src/main/java/org/apache/weex/utils/StaticLayoutProxy.java
new file mode 100644
index 0000000..cacd2b6
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/StaticLayoutProxy.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextDirectionHeuristic;
+import android.text.TextDirectionHeuristics;
+import android.text.TextPaint;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Created by moxun on 2017/9/26.
+ */
+
+public class StaticLayoutProxy {
+  private static Constructor<StaticLayout> layoutConstructor;
+  public static StaticLayout create(CharSequence source, TextPaint paint,
+                                    int width,
+                                    Layout.Alignment align, float spacingmult, float spacingadd,
+                                    boolean includepad, boolean forceRtl) {
+    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2 && forceRtl) {
+      TextDirectionHeuristic textDir = TextDirectionHeuristics.RTL;
+      StaticLayout rtlLayout =  createInternal(source, paint, width, align, textDir, spacingmult, spacingadd, includepad);
+      if (rtlLayout != null) {
+        return rtlLayout;
+      } else {
+        return new StaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad);
+      }
+    }
+    return new StaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad);
+  }
+
+  private static StaticLayout createInternal(CharSequence source, TextPaint paint,
+                                             int width, Layout.Alignment align, TextDirectionHeuristic textDir,
+                                             float spacingmult, float spacingadd,
+                                             boolean includepad) {
+    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
+      return null;
+    } else {
+      try {
+        if (layoutConstructor == null) {
+          Class<StaticLayout> clazz = StaticLayout.class;
+          Constructor<StaticLayout> constructor = clazz.getConstructor(CharSequence.class, TextPaint.class,
+                  int.class, Layout.Alignment.class, TextDirectionHeuristic.class,
+                  float.class, float.class,
+                  boolean.class);
+          layoutConstructor = constructor;
+        }
+        if (layoutConstructor != null) {
+          return layoutConstructor.newInstance(source, paint, width,
+                  align, textDir, spacingmult, spacingadd, includepad);
+        }
+
+      } catch (Throwable e) {
+        e.printStackTrace();
+      }
+    }
+    return null;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/Trace.java b/android/sdk/src/main/java/org/apache/weex/utils/Trace.java
new file mode 100644
index 0000000..0544555
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/Trace.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+/**
+ * Hepler class for systrace.
+ *
+ * Note that this will run only on JBMR2 or later.
+ *
+ * Trace will be enabled in debug production and be disabled in release
+ * production, see build.gradle.
+ * If you want to enable it in release, just set sEnabled to true.
+ */
+public class Trace {
+  private static final String TAG = "Weex_Trace";
+  private abstract static class AbstractTrace {
+    abstract void beginSection(String sectionName);
+    abstract void endSection();
+  }
+
+  private static final AbstractTrace sTrace;
+  private static final boolean sEnabled;
+
+  // Pick the correct trace class to handle tracing.
+  static {
+    // If you want to enable it in release, just set sEnabled to true.
+    // If you turn sEnabled on, weex would trace logs on Java side
+    // as well as on V8 side, please take care of turning sEnabled on
+    // to avoid performance impact.
+    // FIXME: weex sdk may use another build files to build and cause
+    // compiling errors if these build files don't contain any
+    // ENABLE_TRACE, just comment out the line below.
+    //sEnabled = com.taobao.weappplus_sdk.BuildConfig.ENABLE_TRACE;
+    sEnabled = false;
+
+    if (sEnabled == true && OsVersion.isAtLeastJB_MR2()) {
+      sTrace = new TraceJBMR2();
+    } else {
+      sTrace = new TraceDummy();
+    }
+  }
+
+  public static final boolean getTraceEnabled() {
+    return sEnabled;
+  }
+
+  /**
+   * Writes a trace message to indicate that a given section of code has begun.
+   * This call must be followed by a corresponding call to {@link #endSection()}
+   * on the same thread.
+   *
+   * <p class="note"> If sectionName contains '|', '\n' and '\0', these characters
+   * will be repaced with a space character.
+   *
+   * @param sectionName The name of code section to appear in the trace.
+   */
+  public static void beginSection(String sectionName) {
+    android.util.Log.i(TAG, "beginSection() " + sectionName);
+    sTrace.beginSection(sectionName);
+  }
+
+  /**
+   * Writes a trace message to indicate that a given section of code has ended.
+   * This call must be preceeded by a corresponding call to {@link #beginSection(String)}
+   * on the same thread.
+   */
+  public static void endSection() {
+    sTrace.endSection();
+    android.util.Log.i(TAG, "endSection()");
+  }
+
+  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+  private static final class TraceJBMR2 extends AbstractTrace {
+    @Override
+    void beginSection(String sectionName) {
+      android.os.Trace.beginSection(sectionName);
+    }
+
+    @Override
+    void endSection() {
+      android.os.Trace.endSection();
+    }
+  }
+
+  private static final class TraceDummy extends AbstractTrace {
+    @Override
+    void beginSection(String sectionName) {
+    }
+
+    @Override
+    void endSection() {
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/TypefaceUtil.java b/android/sdk/src/main/java/org/apache/weex/utils/TypefaceUtil.java
new file mode 100644
index 0000000..a028c4d
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/TypefaceUtil.java
@@ -0,0 +1,297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.content.Intent;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.support.v4.content.LocalBroadcastManager;
+import android.text.TextUtils;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXHttpAdapter;
+import org.apache.weex.common.WXRequest;
+import org.apache.weex.common.WXResponse;
+import org.apache.weex.dom.WXStyle;
+import org.apache.weex.font.FontAdapter;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by sospartan on 7/13/16.
+ */
+public class TypefaceUtil {
+  public static final String FONT_CACHE_DIR_NAME = "font-family";
+  private final static String TAG = "TypefaceUtil";
+  private final static Map<String, FontDO> sCacheMap = new HashMap<>(); //Key: fontFamilyName
+
+  public static final String ACTION_TYPE_FACE_AVAILABLE = "type_face_available";
+
+  public static void putFontDO(FontDO fontDO) {
+    if (fontDO != null && !TextUtils.isEmpty(fontDO.getFontFamilyName())) {
+      sCacheMap.put(fontDO.getFontFamilyName(), fontDO);
+    }
+  }
+
+  public static void registerNativeFont(Map<String, Typeface> fonts) {
+    if (fonts != null && fonts.size() > 0) {
+      for (Map.Entry<String, Typeface> font : fonts.entrySet()) {
+        FontDO fontDO = new FontDO(font.getKey(), font.getValue());
+        putFontDO(fontDO);
+        if (WXEnvironment.isApkDebugable()){
+          WXLogUtils.d("TypefaceUtil", "register new typeface: " + font.getKey());
+        }
+      }
+    }
+  }
+
+  public static FontDO getFontDO(String fontFamilyName) {
+    return sCacheMap.get(fontFamilyName);
+  }
+
+  public static void removeFontDO(String fontFamilyName) {
+    sCacheMap.remove(fontFamilyName);
+  }
+
+  public static void applyFontStyle(Paint paint, int style, int weight, String family) {
+    int oldStyle;
+    Typeface typeface = paint.getTypeface();
+    if (typeface == null) {
+      oldStyle = 0;
+    } else {
+      oldStyle = typeface.getStyle();
+    }
+
+    int want = 0;
+    if ((weight == Typeface.BOLD)
+            || ((oldStyle & Typeface.BOLD) != 0 && weight == WXStyle.UNSET)) {
+      want |= Typeface.BOLD;
+    }
+
+    if ((style == Typeface.ITALIC)
+            || ((oldStyle & Typeface.ITALIC) != 0 && style == WXStyle.UNSET)) {
+      want |= Typeface.ITALIC;
+    }
+
+    if (family != null) {
+      typeface = getOrCreateTypeface(family, want);
+    }
+
+    if (typeface != null) {
+      paint.setTypeface(Typeface.create(typeface, want));
+    } else {
+      paint.setTypeface(Typeface.defaultFromStyle(want));
+    }
+  }
+
+  public static Typeface getOrCreateTypeface(String family, int style) {
+    FontDO fontDo = sCacheMap.get(family);
+    if (fontDo != null && fontDo.getTypeface() != null) {
+      return fontDo.getTypeface();
+    }
+
+    return Typeface.create(family, style);
+  }
+
+  private static void loadFromAsset(FontDO fontDo,String path){
+    try {
+      Typeface typeface = Typeface.createFromAsset(WXEnvironment.getApplication().getAssets(), path);
+      if (typeface != null) {
+        if(WXEnvironment.isApkDebugable()) {
+          WXLogUtils.d(TAG, "load asset file success");
+        }
+        fontDo.setState(FontDO.STATE_SUCCESS);
+        fontDo.setTypeface(typeface);
+      } else {
+        WXLogUtils.e(TAG, "Font asset file not found " + fontDo.getUrl());
+      }
+    } catch (Exception e) {
+      WXLogUtils.e(TAG, e.toString());
+    }
+  }
+
+  public static void loadTypeface(final FontDO fontDo, boolean notify) {
+    if (fontDo != null && fontDo.getTypeface() == null &&
+            (fontDo.getState() == FontDO.STATE_FAILED || fontDo.getState() == FontDO.STATE_INIT)) {
+      fontDo.setState(FontDO.STATE_LOADING);
+      if (fontDo.getType() == FontDO.TYPE_LOCAL) {
+        Uri uri = Uri.parse(fontDo.getUrl());
+        loadFromAsset(fontDo,uri.getPath().substring(1));//exclude slash
+      } else if (fontDo.getType() == FontDO.TYPE_NETWORK) {
+        final String url = fontDo.getUrl();
+        final String fontFamily = fontDo.getFontFamilyName();
+        final String fileName = WXFileUtils.md5(url);
+        //url.replace('/', '_').replace(':', '_');
+        File dir = new File(getFontCacheDir());
+        if(!dir.exists()){
+          dir.mkdirs();
+        }
+        final String fullPath =  dir.getAbsolutePath()+ File.separator +fileName;
+        if (!loadLocalFontFile(fullPath, fontFamily, false)) {
+          downloadFontByNetwork(url, fullPath, fontFamily);
+        }
+      } else if (fontDo.getType() == FontDO.TYPE_FILE || fontDo.getType() == FontDO.TYPE_BASE64) {
+        boolean result = loadLocalFontFile(fontDo.getUrl(), fontDo.getFontFamilyName(), false);
+        if (!result) {
+          fontDo.setState(FontDO.STATE_FAILED);
+        }
+      }
+      return;
+    }
+    if(notify){
+         notifyFontAvailable(false, fontDo);
+    }
+  }
+
+  private static void downloadFontByNetwork(final String url, final String fullPath, final String fontFamily) {
+    IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter();
+    if (adapter == null) {
+      WXLogUtils.e(TAG, "downloadFontByNetwork() IWXHttpAdapter == null");
+      return;
+    }
+    WXRequest request = new WXRequest();
+    request.url = url;
+    request.method = "GET";
+    adapter.sendRequest(request, new IWXHttpAdapter.OnHttpListener() {
+      @Override
+      public void onHttpStart() {
+        if(WXEnvironment.isApkDebugable()) {
+          WXLogUtils.d(TAG, "downloadFontByNetwork begin url:" + url);
+        }
+      }
+
+      @Override
+      public void onHeadersReceived(int statusCode, Map<String, List<String>> headers) {
+
+      }
+
+      @Override
+      public void onHttpUploadProgress(int uploadProgress) {
+
+      }
+
+      @Override
+      public void onHttpResponseProgress(int loadedLength) {
+
+      }
+
+      @Override
+      public void onHttpFinish(WXResponse response) {
+        int statusCode = 0;
+        if (!TextUtils.isEmpty(response.statusCode)) {
+          try {
+            statusCode = Integer.parseInt(response.statusCode);
+          } catch (NumberFormatException e) {
+            statusCode = 0;
+            WXLogUtils.e(TAG, "IWXHttpAdapter onHttpFinish statusCode:" + response.statusCode);
+          }
+        }
+        boolean result;
+        if (statusCode >= 200 && statusCode <= 299 && response.originalData != null) {
+          result = WXFileUtils.saveFile(fullPath, response.originalData, WXEnvironment.getApplication());
+          if (result) {
+            result = loadLocalFontFile(fullPath, fontFamily, true);
+          } else {
+            if(WXEnvironment.isApkDebugable()) {
+              WXLogUtils.d(TAG, "downloadFontByNetwork() onHttpFinish success, but save file failed.");
+            }
+          }
+        } else {
+          result = false;
+        }
+
+        if (!result) {
+          FontDO fontDO = sCacheMap.get(fontFamily);
+          if (fontDO != null) {
+            fontDO.setState(FontDO.STATE_FAILED);
+          }
+        }
+      }
+    });
+  }
+
+  private static boolean loadLocalFontFile(final String path, final String fontFamily, boolean hasNetworkDowload) {
+    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(fontFamily)) {
+      return false;
+    }
+    try {
+      File file = new File(path);
+      if (!file.exists()) {
+        return false;
+      }
+      Typeface typeface = Typeface.createFromFile(path);
+      if (typeface != null) {
+        final FontDO fontDo = sCacheMap.get(fontFamily);
+        if (fontDo != null) {
+          fontDo.setState(FontDO.STATE_SUCCESS);
+          fontDo.setTypeface(typeface);
+          fontDo.setFilePath(path);
+          if(WXEnvironment.isApkDebugable()) {
+            WXLogUtils.d(TAG, "load local font file success");
+          }
+
+          if(hasNetworkDowload) {
+            /**
+             * wxtext may be measured when font not load, when register broadcast receiver,
+             * this broadcast has been send, which cause textview not rendered right.
+             * delay broadcast ensure text will render right
+             * */
+            WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() {
+              @Override
+              public void run() {
+               notifyFontAvailable(true, fontDo);
+              }
+            }, 100);
+          }else{
+             notifyFontAvailable(true, fontDo);
+          }
+          return true;
+        }
+      } else {
+        WXLogUtils.e(TAG, "load local font file failed, can't create font.");
+      }
+    } catch (Exception e) {
+      WXLogUtils.e(TAG, e.toString());
+    }
+    return false;
+  }
+
+  private static void notifyFontAvailable(boolean sendBroadcast, FontDO fontDO){
+    if(sendBroadcast){
+      Intent intent = new Intent(ACTION_TYPE_FACE_AVAILABLE);
+      intent.putExtra("fontFamily", fontDO.getFontFamilyName());
+      intent.putExtra("filePath", fontDO.getFilePath());
+      intent.putExtra("fontUrl", fontDO.getUrl());
+      LocalBroadcastManager.getInstance(WXEnvironment.getApplication()).sendBroadcast(intent);
+    }
+    FontAdapter fontAdapter = WXSDKManager.getInstance().getFontAdapter();
+    if(fontAdapter != null){
+        fontAdapter.onFontLoad(fontDO.getFontFamilyName(), fontDO.getUrl(), fontDO.getFilePath());
+    }
+  }
+
+  private static String getFontCacheDir() {
+    return WXEnvironment.getApplication().getCacheDir() + "/" + FONT_CACHE_DIR_NAME;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXDataStructureUtil.java b/android/sdk/src/main/java/org/apache/weex/utils/WXDataStructureUtil.java
new file mode 100644
index 0000000..72b45ea
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXDataStructureUtil.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Guava Authors
+ *
+ * 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 org.apache.weex.utils;
+
+import java.util.HashMap;
+
+public class WXDataStructureUtil {
+
+  /**
+   * The largest power of two that can be represented as an {@code int}.
+   */
+  private static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
+
+  /**
+   * Creates a {@code HashMap} instance, with a high enough "initial capacity" that it <i>should</i>
+   * hold {@code expectedSize} elements without growth. This behavior cannot be broadly guaranteed,
+   * but it is observed to be true for OpenJDK 1.7. It also can't be guaranteed that the method
+   * isn't inadvertently <i>oversizing</i> the returned map.
+   *
+   * @param expectedSize the number of entries you expect to add to the returned map
+   * @return a new, empty {@code HashMap} with enough capacity to hold {@code expectedSize} entries
+   * without resizing
+   * @throws IllegalArgumentException if {@code expectedSize} is negative
+   */
+  public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {
+    return new HashMap<>(capacity(expectedSize));
+  }
+
+  /**
+   * Returns a capacity that is sufficient to keep the map from being resized as long as it grows no
+   * larger than expectedSize and the load factor is >= its default (0.75).
+   */
+  private static int capacity(int expectedSize) {
+    if (expectedSize < 3) {
+      checkNonnegative(expectedSize, "expectedSize");
+      return expectedSize + 1;
+    }
+    if (expectedSize < MAX_POWER_OF_TWO) {
+      // This is the calculation used in JDK8 to resize when a putAll
+      // happens; it seems to be the most conservative calculation we
+      // can make.  0.75 is the default load factor.
+      return (int) ((float) expectedSize / 0.75F + 1.0F);
+    }
+    return Integer.MAX_VALUE; // any large value
+  }
+
+  private static int checkNonnegative(int value, String name) {
+    if (value < 0) {
+      throw new IllegalArgumentException(name + " cannot be negative but was: " + value);
+    }
+    return value;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXDeviceUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXDeviceUtils.java
new file mode 100644
index 0000000..e6ff59f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXDeviceUtils.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.content.Context;
+import android.os.Build;
+
+public class WXDeviceUtils {
+
+
+    public static boolean isAutoResize(Context context){
+        if(context == null){
+            return false;
+        }
+        return isMateX(context) || isGalaxyFold(context);
+    }
+
+    /**
+     * Mate X
+     * */
+    public static boolean isMateX(Context context) {
+        return "HUAWEI".equalsIgnoreCase(Build.BRAND) && ("unknownRLI".equalsIgnoreCase(Build.DEVICE) || ("HWTAH".equalsIgnoreCase(Build.DEVICE)));
+    }
+
+
+    /**
+     * Galaxy Fopld
+     * */
+    public static boolean isGalaxyFold(Context context) {
+
+        if("samsung".equalsIgnoreCase(Build.BRAND) && "SM-F9000".equalsIgnoreCase(Build.MODEL)) {
+            return true;
+        }
+
+        return false;
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXDomUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXDomUtils.java
new file mode 100644
index 0000000..2d26a27
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXDomUtils.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.support.annotation.NonNull;
+import org.apache.weex.dom.CSSConstants;
+import org.apache.weex.dom.CSSShorthand.EDGE;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.dom.CSSShorthand;
+
+public class WXDomUtils {
+
+  /**
+   * Get the content width of the dom.
+   * @return the width of the dom that excludes left-padding, left-border-width,
+   * right-border-width and right-padding.
+   */
+  public static float getContentWidth(WXComponent component) {
+    float rawWidth = component.getLayoutWidth();
+    float leftPadding, rightPadding, leftBorder, rightBorder;
+    CSSShorthand padding = component.getPadding();
+    CSSShorthand border = component.getBorder();
+
+    if (!CSSConstants.isUndefined((leftPadding = padding.get(CSSShorthand.EDGE.LEFT)))) {
+      rawWidth -= leftPadding;
+    }
+    if (!CSSConstants.isUndefined((rightPadding = padding.get(CSSShorthand.EDGE.RIGHT)))) {
+      rawWidth -= rightPadding;
+    }
+
+    if (!CSSConstants.isUndefined(leftBorder = border.get(CSSShorthand.EDGE.LEFT))) {
+      rawWidth -= leftBorder;
+    }
+    if (!CSSConstants.isUndefined(rightBorder = border.get(CSSShorthand.EDGE.RIGHT))) {
+      rawWidth -= rightBorder;
+    }
+    return rawWidth;
+  }
+
+  /**
+   * Get the content height of the dom.
+   * @return the height of the dom that excludes top-padding, top-border-width, bottom-padding
+   * and bottom-border-width.
+   */
+  public static float getContentHeight(WXComponent component) {
+    float rawHeight = component.getLayoutHeight();
+    float topPadding, bottomPadding, topBorder, bottomBorder;
+    CSSShorthand padding = component.getPadding();
+    CSSShorthand border = component.getBorder();
+
+    if (!CSSConstants.isUndefined((topPadding = padding.get(CSSShorthand.EDGE.TOP)))) {
+      rawHeight -= topPadding;
+    }
+    if (!CSSConstants.isUndefined((bottomPadding = padding.get(CSSShorthand.EDGE.BOTTOM)))) {
+      rawHeight -= bottomPadding;
+    }
+
+    if (!CSSConstants.isUndefined(topBorder = border.get(CSSShorthand.EDGE.TOP))) {
+      rawHeight -= topBorder;
+    }
+    if (!CSSConstants.isUndefined(bottomBorder = border.get(CSSShorthand.EDGE.BOTTOM))) {
+      rawHeight -= bottomBorder;
+    }
+    return rawHeight;
+  }
+
+  public static float getContentWidth(
+      @NonNull CSSShorthand padding,
+      @NonNull CSSShorthand border,
+      float layoutWidth){
+    float leftPadding, rightPadding, leftBorder, rightBorder;
+
+    if (!CSSConstants.isUndefined((leftPadding = padding.get(EDGE.LEFT)))) {
+      layoutWidth -= leftPadding;
+    }
+    if (!CSSConstants.isUndefined((rightPadding = padding.get(EDGE.RIGHT)))) {
+      layoutWidth -= rightPadding;
+    }
+
+    if (!CSSConstants.isUndefined(leftBorder = border.get(EDGE.LEFT))) {
+      layoutWidth -= leftBorder;
+    }
+    if (!CSSConstants.isUndefined(rightBorder = border.get(EDGE.RIGHT))) {
+      layoutWidth -= rightBorder;
+    }
+    return layoutWidth;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXExceptionUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXExceptionUtils.java
new file mode 100644
index 0000000..84705f2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXExceptionUtils.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.adapter.IWXJSExceptionAdapter;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXErrorCode.ErrorGroup;
+import org.apache.weex.common.WXJSExceptionInfo;
+import org.apache.weex.common.WXPerformance;
+import org.apache.weex.performance.WXAnalyzerDataTransfer;
+import org.apache.weex.performance.WXInstanceApm;
+import org.apache.weex.performance.WXStateRecord;
+
+/**
+ * Created on 2017/10/13.
+ */
+
+public class WXExceptionUtils {
+
+    private static Set<String> sGlobalExceptionRecord = new CopyOnWriteArraySet<String>();
+
+	/**
+	 * degradeUrl for degrade case
+	 */
+	public static String degradeUrl = "BundleUrlDefaultDegradeUrl";
+
+	private static boolean checkNeedReportCauseRepeat(String instanceId, WXErrorCode errCode,String exception){
+
+	    if (TextUtils.isEmpty(exception)){
+	        return true;
+        }
+
+        if (null != errCode && errCode.getErrorGroup() != ErrorGroup.JS){
+	        return true;
+        }
+
+        if (TextUtils.isEmpty(instanceId)){
+            instanceId = "instanceIdNull";
+        }
+
+        String targetException = exception.length() > 200 ?exception.substring(0,200) : exception;
+        Set<String> recordExceptionHistory= null;
+
+        WXSDKInstance instance =  WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+        if (null == instance){
+            recordExceptionHistory = sGlobalExceptionRecord;
+        }else {
+            recordExceptionHistory =  instance.getApmForInstance().exceptionRecord;
+        }
+
+        if (null == recordExceptionHistory){
+            return true;
+        }
+
+        if (recordExceptionHistory.contains(targetException)){
+            return false;
+        }
+        recordExceptionHistory.add(targetException);
+        return true;
+    }
+
+
+
+
+	/**
+	 * commitCriticalExceptionRT eg:JsRuntime Exception or JsFramework Init Exception
+	 * @param instanceId
+	 * @param errCode
+	 * @param function
+	 * @param exception
+	 * @param extParams
+	 */
+	public static void commitCriticalExceptionRT(@Nullable final String instanceId,
+												 @Nullable final WXErrorCode errCode,
+												 @Nullable final String function,
+												 @Nullable final String exception,
+												 @Nullable final Map<String,String> extParams ) {
+
+        try {
+            WXLogUtils.e("weex","commitCriticalExceptionRT :"+errCode+"exception"+exception);
+            WXStateRecord.getInstance().recordException(instanceId,exception);
+            IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
+            boolean doCheck = true;
+            if (null != configAdapter){
+                String value = configAdapter.getConfig("wxapm","check_repeat_report","true");
+                doCheck = "true".equalsIgnoreCase(value);
+            }
+            boolean doReport =true;
+            if (doCheck){
+                doReport = checkNeedReportCauseRepeat(instanceId,errCode,exception);
+            }
+            if (!doReport){
+                return;
+            }
+        }catch (Throwable e){
+            e.printStackTrace();
+        }
+
+
+		commitCriticalExceptionWithDefaultUrl(
+		    "BundleUrlDefault",
+            instanceId,
+            errCode,
+            function,
+            exception,
+            extParams
+        );
+	}
+
+    public static void commitCriticalExceptionWithDefaultUrl(
+        @Nullable final String defaultUrl,
+        @Nullable final String instanceId,
+        @Nullable final WXErrorCode errCode,
+        @Nullable final String function,
+        @Nullable final String exception,
+        @Nullable final Map<String,String> extParams
+    ){
+        IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
+        WXSDKInstance instance = null;
+        WXJSExceptionInfo exceptionCommit;
+        String bundleUrlCommit = TextUtils.isEmpty(defaultUrl)?"BundleUrlDefault":defaultUrl;
+        String instanceIdCommit = "InstanceIdDefalut";
+        String exceptionMsgCommit = exception;
+        Map<String, String> commitMap = extParams;
+        if (null == commitMap){
+            commitMap = new HashMap<>();
+        }
+        commitMap.put("wxSdkInitStartTime", String.valueOf(WXEnvironment.sSDKInitStart));
+        commitMap.put("wxSDKInitCostTime", String.valueOf(WXEnvironment.sSDKInitTime));
+        commitMap.put("wxSDKCurExceptionTime", String.valueOf(System.currentTimeMillis()));
+        commitMap.put("wxUseRuntimeApi",String.valueOf(WXEnvironment.sUseRunTimeApi));
+        if (!TextUtils.isEmpty(instanceId)) {
+            instanceIdCommit = instanceId;
+            instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
+
+            if (null != instance) {
+                bundleUrlCommit = instance.getApmForInstance().reportPageName;
+                Object loadLength = instance.getApmForInstance().extInfo.get(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH);
+                String loadLengthStr = (loadLength instanceof Integer)?String.valueOf(loadLength):"unknownLength";
+                commitMap.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadLengthStr);
+                commitMap.put("templateInfo",instance.getTemplateInfo());
+                if (TextUtils.isEmpty(bundleUrlCommit) || bundleUrlCommit.equals(WXPerformance.DEFAULT)) {
+                    if (!TextUtils.equals(degradeUrl, "BundleUrlDefaultDegradeUrl")) {
+                        bundleUrlCommit = degradeUrl;
+                    } else
+                        bundleUrlCommit = WXSDKInstance.requestUrl;
+                }
+                for (Map.Entry<String,String> entry: instance.getContainerInfo().entrySet()){
+                    commitMap.put(entry.getKey(),entry.getValue());
+                }
+                commitMap.put("wxStageList",convertStageToStr(instance));
+                String bundleTemplate = instance.getTemplate();
+                if (null == bundleTemplate){
+                    bundleTemplate = "has recycle by gc";
+                }else {
+                    int length = bundleTemplate.length();
+                    bundleTemplate = bundleTemplate.substring(0,Math.min(length,300));
+                }
+                commitMap.put("wxTemplateOfBundle",bundleTemplate);
+
+                Long pageStartTime = instance.getApmForInstance().stageMap.get(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
+                if (null == pageStartTime){
+                    pageStartTime = instance.getApmForInstance().stageMap.get(WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN);
+                }
+                if (null != pageStartTime){
+                    commitMap.put("wxUseTime", String.valueOf(WXUtils.getFixUnixTime() - pageStartTime));
+                }
+            }
+        } else {//instance is null for instance id is null
+            if (commitMap.size() > 0) {
+                bundleUrlCommit = TextUtils.isEmpty(commitMap.get("weexUrl")) ? commitMap.get("weexUrl")
+                    : commitMap.get("bundleUrl");
+            }
+        }
+
+        String illegalValue = commitMap.get("errorCode");
+        if (null != illegalValue && illegalValue.length()>200){
+            commitMap.remove("errorCode");
+        }
+
+        exceptionCommit = new WXJSExceptionInfo(instanceIdCommit, bundleUrlCommit, errCode, function, exceptionMsgCommit, commitMap);
+        if (adapter != null) {
+            adapter.onJSException(exceptionCommit);
+        }
+
+        WXAnalyzerDataTransfer.transferError(exceptionCommit, instanceId);
+    }
+
+    private static String convertStageToStr(WXSDKInstance instance) {
+        if (null == instance || null == instance.getApmForInstance() || instance.getApmForInstance().stageMap.isEmpty()) {
+            return "noStageRecord";
+        }
+        List<Entry<String, Long>> list = new ArrayList<>(instance.getApmForInstance().stageMap.entrySet());
+        Collections.sort(list, new Comparator<Entry<String, Long>>() {
+            @Override
+            public int compare(Entry<String, Long> o1, Entry<String, Long> o2) {
+                return (int)(o1.getValue() - o2.getValue());
+            }
+        });
+
+        StringBuilder builder = new StringBuilder();
+        for (Map.Entry<String, Long> entry : list) {
+            builder.append(entry.getKey()).append(':').append(entry.getValue()).append("->");
+        }
+        return builder.toString();
+    }
+
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXFileUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXFileUtils.java
new file mode 100644
index 0000000..feaec62
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXFileUtils.java
@@ -0,0 +1,302 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Base64;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import org.apache.weex.WXEnvironment;
+
+public class WXFileUtils {
+
+  /**
+   * Load file in device directory, if not exist, load from asset directory.
+   * @param path FilePath
+   * @param context Weex Context
+   * @return the Content of the file
+   */
+  public static String loadFileOrAsset(String path, Context context) {
+    if (!TextUtils.isEmpty(path)) {
+      File file = new File(path);
+      if (file.exists()) {
+        try {
+          FileInputStream fis = new FileInputStream(file);
+          return readStreamToString(fis);
+        } catch (FileNotFoundException e) {
+          e.printStackTrace();
+        }
+      } else {
+        return loadAsset(path, context);
+      }
+    }
+    return "";
+  }
+
+  /**
+   * Load file in asset directory.
+   * @param path FilePath
+   * @param context Weex Context
+   * @return the Content of the file
+   */
+  public static String loadAsset(String path, Context context) {
+    if (context == null || TextUtils.isEmpty(path)) {
+      return null;
+    }
+    InputStream inputStream = null;
+    try {
+      inputStream = context.getAssets().open(path);
+      return readStreamToString(inputStream);
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    return "";
+  }
+
+  public static String readStreamToString(InputStream inputStream) {
+    BufferedReader bufferedReader = null;
+    try {
+      StringBuilder builder = new StringBuilder(inputStream.available() + 10);
+      bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
+      char[] data = new char[4096];
+      int len = -1;
+      while ((len = bufferedReader.read(data)) > 0) {
+        builder.append(data, 0, len);
+      }
+
+      return builder.toString();
+    } catch (IOException e) {
+      e.printStackTrace();
+      WXLogUtils.e("", e);
+    } finally {
+      try {
+        if (bufferedReader != null)
+          bufferedReader.close();
+      } catch (IOException e) {
+        WXLogUtils.e("WXFileUtils loadAsset: ", e);
+      }
+      try {
+        if (inputStream != null)
+          inputStream.close();
+      } catch (IOException e) {
+        WXLogUtils.e("WXFileUtils loadAsset: ", e);
+      }
+    }
+
+    return "";
+  }
+
+  public static byte[] readBytesFromAssets(String path, Context context) {
+    if (context == null || TextUtils.isEmpty(path)) {
+      return null;
+    }
+    InputStream inputStream = null;
+    try {
+      inputStream = context.getAssets().open(path);
+      byte[] data = new byte[4096];
+      int length = inputStream.read(data);
+      byte[] result = new byte[length];
+      System.arraycopy(data, 0, result, 0, length);
+      return result;
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    return null;
+  }
+
+  public static boolean saveFile(String path, byte[] content, Context context) {
+    if (TextUtils.isEmpty(path) || content == null || context == null) {
+      return false;
+    }
+    FileOutputStream outStream = null;
+    try {
+      outStream = new FileOutputStream(path);
+      outStream.write(content);
+      return true;
+    } catch (Exception e) {
+      WXLogUtils.e("WXFileUtils saveFile: " + WXLogUtils.getStackTrace(e));
+    } finally {
+      if (outStream != null) {
+        try {
+          outStream.close();
+        } catch (IOException e) {
+          e.printStackTrace();
+        }
+      }
+    }
+    return false;
+  }
+
+  public static String md5(String  template){
+    try {
+      if(template == null){
+        return  "";
+      }
+      return  md5(template.getBytes("UTF-8"));
+    } catch (UnsupportedEncodingException e) {
+      return  "";
+    }
+  }
+
+  public static String md5(byte[] bts){
+    try {
+      MessageDigest digest = MessageDigest.getInstance("MD5");
+      digest.update(bts);
+      BigInteger bigInt = new BigInteger(1, digest.digest());
+      return  bigInt.toString(16);
+    } catch (NoSuchAlgorithmException e) {;
+      return  "";
+    }
+  }
+
+  public static String base64Md5(String  template){
+    try {
+      if(template == null){
+        return  "";
+      }
+      return  base64Md5(template.getBytes("UTF-8"));
+    } catch (UnsupportedEncodingException e) {
+      return  "";
+    }
+  }
+
+  public static String base64Md5(byte[] bts){
+    try {
+      MessageDigest digest = MessageDigest.getInstance("MD5");
+      digest.update(bts);
+      return Base64.encodeToString(digest.digest(), Base64.NO_WRAP);
+    } catch (NoSuchAlgorithmException e) {;
+      return  "";
+    }
+  }
+
+  public static void extractSo(String apkFile, String path) throws IOException {
+    ZipFile zip = new ZipFile(apkFile);
+    InputStream zipInputStream = new BufferedInputStream(new FileInputStream(apkFile));
+    ZipInputStream zin = new ZipInputStream(zipInputStream);
+    ZipEntry zipEntry;
+    while ((zipEntry = zin.getNextEntry()) != null) {
+      if(zipEntry.isDirectory()){
+        continue;
+      }
+      if(zipEntry.getName().contains("lib/armeabi/") &&
+              (zipEntry.getName().contains("weex") || zipEntry.getName().equals(
+                  String.format(Locale.ENGLISH, "lib%s.so", WXEnvironment.CORE_JSC_SO_NAME)))){
+        String[] fileNames = zipEntry.getName().split("/");
+        String fileName = fileNames[fileNames.length - 1];
+        InputStream inputStream = zip.getInputStream(zipEntry);
+        byte[] data = new byte[1024];
+        File zipFile = new File(path + "/" + fileName);
+        if(zipFile.exists()) {
+          zipFile.delete();
+        }
+
+        zipFile.createNewFile();
+
+        FileOutputStream outputStream =new FileOutputStream(zipFile);
+        while (inputStream.read(data) != -1) {
+          outputStream.write(data);
+        }
+        outputStream.close();
+
+      }
+    }
+    zin.closeEntry();
+  }
+
+  public static void copyFile(File oldFile, File newFile) {
+    FileInputStream inputStream = null;
+    FileOutputStream outputStream = null;
+    try {
+      inputStream = new FileInputStream(oldFile);
+      byte[] data = new byte[1024];
+      outputStream = new FileOutputStream(newFile);
+      while (inputStream.read(data) != -1) {
+        outputStream.write(data);
+      }
+      inputStream.close();
+      outputStream.close();
+    } catch (Exception e) {
+      WXLogUtils.e("copyFile " + e.getMessage() + ": " + oldFile.getAbsolutePath() + ": " + newFile.getAbsolutePath());
+      if (inputStream != null) {
+        try {
+          inputStream.close();
+        } catch (IOException e1) {
+          e1.printStackTrace();
+        }
+      }
+
+      if (outputStream != null) {
+        try {
+          outputStream.close();
+        } catch (IOException e1) {
+          e1.printStackTrace();
+        }
+      }
+    }
+  }
+
+  public static void copyFileWithException(File oldFile,File newFile ) throws Exception{
+    FileInputStream inputStream = null;
+    FileOutputStream outputStream = null;
+    try {
+      inputStream = new FileInputStream(oldFile);
+      byte[] data = new byte[1024];
+      outputStream = new FileOutputStream(newFile);
+      while (inputStream.read(data) != -1) {
+        outputStream.write(data);
+      }
+    }catch (Exception e){
+      throw e;
+    }finally {
+      closeIo(inputStream);
+      closeIo(outputStream);
+    }
+  }
+
+  public static void closeIo(Closeable c){
+    if (null == c){
+      return;
+    }
+    try {
+      c.close();
+    }catch (Throwable e){
+      e.printStackTrace();
+    }
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXInterception.java b/android/sdk/src/main/java/org/apache/weex/utils/WXInterception.java
new file mode 100644
index 0000000..04bdcab
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXInterception.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class WXInterception {
+
+  private WXInterception() {
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> T proxy(final Object delegatee, final Class<T> interface_class, final InterceptionHandler<T> handler) throws IllegalArgumentException {
+    if (delegatee instanceof Intercepted) {
+      return (T) delegatee;
+    }
+    handler.setDelegate((T) delegatee);
+    return (T) Proxy.newProxyInstance(WXInterception.class.getClassLoader(), new Class<?>[]{interface_class, Intercepted.class}, handler);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> T proxy(final Object delegatee, final InterceptionHandler<T> handler, final Class<?>... interfaces) throws IllegalArgumentException {
+    //if (Proxy.isProxyClass(delegatee.getClass())) return (T) delegatee;
+    handler.setDelegate((T) delegatee);
+    return (T) Proxy.newProxyInstance(WXInterception.class.getClassLoader(), interfaces, handler);
+  }
+
+  private interface Intercepted {
+
+  }        // A mark to identify our proxy class
+
+  /**
+   * Derive this class and override {@link #invoke(Object, Method, Object[])} to implement an
+   * interception handler.
+   */
+  public abstract static class InterceptionHandler<T> implements InvocationHandler {
+
+    private T mDelegate;
+
+    /**
+     * Derived class should override this method and call <code>super.invoke(...)</code> to delegate the
+     * procedure to original delegate instance if needed.
+     *
+     * @param proxy is ignored, instead the actual delegate instance will be used to invoke this method on.
+     */
+    @Override
+    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+      try {
+        return method.invoke(delegate(), args);
+      } catch (IllegalArgumentException e) {/* Should never happen */
+        WXLogUtils.e("", e);
+        return null;
+      } catch (IllegalAccessException e) {/* Should never happen */
+        WXLogUtils.e("", e);
+        return null;
+      } catch (InvocationTargetException e) {
+        throw e.getTargetException();
+      }
+    }
+
+    protected T delegate() {
+      return mDelegate;
+    }
+
+    void setDelegate(final T delegate) {
+      mDelegate = delegate;
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXJsonUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXJsonUtils.java
new file mode 100644
index 0000000..629879b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXJsonUtils.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+
+import android.support.annotation.NonNull;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.common.WXRuntimeException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Tool for parse JSON
+ */
+public class WXJsonUtils {
+
+
+  public @NonNull static <T> List<T> getList(String json, Class<T> clazz) {
+    List<T> result = null;
+    try {
+      result = JSONObject.parseArray(json, clazz);
+    } catch (Exception e) {
+      e.printStackTrace();
+      result = new ArrayList<>();
+    }
+    return result;
+  }
+
+  public @NonNull static String fromObjectToJSONString(Object obj, boolean WriteNonStringKeyAsString){
+    try {
+      if(WriteNonStringKeyAsString) {
+        return JSON.toJSONString(obj, SerializerFeature.WriteNonStringKeyAsString);
+      }else {
+        return JSON.toJSONString(obj);
+      }
+    }catch(Exception e){
+      if(WXEnvironment.isApkDebugable()){
+        throw new WXRuntimeException("fromObjectToJSONString parse error!");
+      }
+      WXLogUtils.e("fromObjectToJSONString error:", e);
+      return "{}";
+    }
+  }
+  public @NonNull static String fromObjectToJSONString(Object obj) {
+
+    return fromObjectToJSONString(obj,false);
+  }
+
+  /**
+   * Put the map info in the JSONObject to the container.
+   * This method check for null value in the JSONObject
+   * and won't put the null value in the container.
+   * As {@link ConcurrentHashMap#putAll(Map)} will throws an exception if the key or value to
+   * be put is null, it is necessary to invoke this method as replacement of
+   * {@link Map#putAll(Map)}
+   * @param container container to contain the JSONObject.
+   * @param rawValue jsonObject, contains map info.
+   */
+  public static void putAll(Map<String, Object> container, JSONObject rawValue) {
+    String key;
+    Object value;
+    for (Map.Entry<String, Object> entry : rawValue.entrySet()) {
+      key = entry.getKey();
+      value = entry.getValue();
+      if (key != null && value != null) {
+        container.put(key, value);
+      }
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXLogUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXLogUtils.java
new file mode 100644
index 0000000..6e21f8f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXLogUtils.java
@@ -0,0 +1,338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.performance.WXStateRecord;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class WXLogUtils {
+
+  public static final String WEEX_TAG = "weex";
+  public static final String WEEX_PERF_TAG = "weex_perf";
+
+  private static final String CLAZZ_NAME_LOG_UTIL = "com.taobao.weex.devtools.common.LogUtil";
+
+  private static StringBuilder builder = new StringBuilder(50);
+  private static HashMap<String, Class> clazzMaps = new HashMap<>(2);
+  private static List<JsLogWatcher> jsLogWatcherList;
+  private static LogWatcher sLogWatcher;
+
+  static {
+    clazzMaps.put(CLAZZ_NAME_LOG_UTIL, loadClass(CLAZZ_NAME_LOG_UTIL));
+    jsLogWatcherList = new ArrayList<>();
+  }
+
+  private static Class loadClass(String clazzName) {
+    Class<?> clazz = null;
+    try {
+      clazz = Class.forName(clazzName);
+      if (clazz != null) {
+        clazzMaps.put(clazzName, clazz);
+      }
+    } catch (ClassNotFoundException e) {
+      // ignore
+    }
+    return clazz;
+  }
+
+  public static void renderPerformanceLog(String type, long time) {
+    if (WXEnvironment.isApkDebugable() || WXEnvironment.isPerf()) {
+//      builder.setLength(0);
+//      builder.append("[render time]").append(type).append(":").append(time);
+//      Log.d(WEEX_PERF_TAG, builder.substring(0));
+//      writeConsoleLog("debug", builder.substring(0));
+    }
+  }
+
+  private static void log(String tag, String msg, LogLevel level){
+    if(TextUtils.isEmpty(msg) || TextUtils.isEmpty(tag) || level == null || TextUtils.isEmpty(level.getName())){
+      return;
+    }
+    if (level == LogLevel.ERROR && !TextUtils.isEmpty(msg) && msg.contains("IPCException")){
+      WXStateRecord.getInstance().recordIPCException("ipc",msg);
+    }
+
+    if(sLogWatcher !=null){
+      sLogWatcher.onLog(level.getName(), tag, msg);
+    }
+
+    if (WXEnvironment.isApkDebugable()) {
+      if(level.getValue() - WXEnvironment.sLogLevel.getValue() >= 0) {
+        Log.println(level.getPriority(), tag, msg);
+        writeConsoleLog(level.getName(), msg);
+      }
+      // if not debug level then print log
+    }else {
+      if(level.getValue() - LogLevel.WARN.getValue() >=0 && level.getValue() - WXEnvironment.sLogLevel.getValue() >= 0){
+        Log.println(level.getPriority(),tag, msg);
+      }
+    }
+  }
+
+  public static void v(String msg) {
+    v(WEEX_TAG,msg);
+  }
+
+  public static void d(String msg) {
+    d(WEEX_TAG,msg);
+  }
+
+  public static void d(String tag, byte[] msg) {
+    d(tag, new String(msg));
+  }
+
+  public static void i(String msg) {
+    i(WEEX_TAG,msg);
+  }
+
+  public static void i(String tag, byte[] msg) {
+    i(tag, new String(msg));
+  }
+
+  public static void info(String msg) {
+    i(WEEX_TAG, msg);
+  }
+
+  public static void w(String msg) {
+    w(WEEX_TAG, msg);
+  }
+
+  public static void w(String tag, byte[] msg) {
+    w(tag, new String(msg));
+  }
+
+  public static void e(String msg) {
+    e(WEEX_TAG,msg);
+  }
+
+  public static void e(String tag, byte[] msg) {
+    e(tag, new String(msg));
+  }
+
+  public static void performance(String instanceId, byte[]msg) {
+//    String s = new String(msg);
+//    if(!TextUtils.isEmpty(instanceId)) {
+//      WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+//      if(sdkInstance != null) {
+//        int i = s.indexOf(",");
+//        if(i >=0 && i < s.length()) {
+//          String substring = s.substring(s.indexOf(",") + 1);
+//          LogDetail logDetail = JSON.parseObject(substring,LogDetail.class);
+//          sdkInstance.mTimeCalculator.addLog(logDetail);
+//        }
+//      }
+//    }
+//    Log.e(TIMELINE_TAG, "from WeexCore" + s);
+  }
+
+  public static void wtf(String msg){
+    wtf(WEEX_TAG, msg);
+  }
+
+  public static void d(String tag, String msg) {
+
+    if(!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(msg)){
+      log(tag, msg, LogLevel.DEBUG);
+
+      if(WXEnvironment.isApkDebugable()){//sLogLevel in debug mode is "LogLevel.DEBUG"
+        if ("jsLog".equals(tag) && jsLogWatcherList != null && jsLogWatcherList.size() > 0) {
+          for (JsLogWatcher jsLogWatcher : jsLogWatcherList) {
+            if (msg.endsWith("__DEBUG")) {
+              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__DEBUG", ""));
+            } else if (msg.endsWith("__INFO")) {
+              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__INFO", ""));
+            } else if (msg.endsWith("__WARN")) {
+              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__WARN", ""));
+            } else if (msg.endsWith("__ERROR")) {
+              jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__ERROR", ""));
+            } else {
+              jsLogWatcher.onJsLog(Log.DEBUG, msg);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  private static LogLevel getLogLevel(String level) {
+    switch (level.trim()){
+      case "__ERROR":
+        return LogLevel.ERROR;
+      case "__WARN":
+        return LogLevel.WARN;
+      case "__INFO":
+        return LogLevel.INFO;
+      case "__LOG":
+        return LogLevel.INFO;
+      case "__DEBUG":
+        return LogLevel.DEBUG;
+    }
+    return LogLevel.DEBUG;
+  }
+
+  public static void i(String tag, String msg) {
+    log(tag, msg,LogLevel.INFO);
+  }
+
+  public static void v(String tag, String msg) {
+    log(tag, msg,LogLevel.VERBOSE);
+  }
+
+  public static void w(String tag, String msg) {
+    log(tag, msg,LogLevel.WARN);
+  }
+
+  public static void e(String tag, String msg) {
+    log(tag, msg,LogLevel.ERROR);
+  }
+
+  public static void wtf(String tag, String msg){
+    log(tag, msg, LogLevel.WTF);
+  }
+
+  /**
+   * 'p' for 'Performance', use {@link #WEEX_PERF_TAG}
+   * @param msg
+   */
+  public static void p(String msg) {
+    d(WEEX_PERF_TAG,msg);
+  }
+
+  public static void d(String prefix, Throwable e) {
+    if (WXEnvironment.isApkDebugable()) {
+      d(prefix + getStackTrace(e));
+    }
+  }
+
+  public static void i(String prefix, Throwable e) {
+    if (WXEnvironment.isApkDebugable()) {
+      info(prefix + getStackTrace(e));
+    }
+  }
+
+  public static void v(String prefix, Throwable e) {
+    if (WXEnvironment.isApkDebugable()) {
+      v(prefix + getStackTrace(e));
+    }
+  }
+
+  public static void w(String prefix, Throwable e) {
+    w(prefix + getStackTrace(e));
+
+  }
+
+  public static void e(String prefix, Throwable e) {
+    e(prefix + getStackTrace(e));
+
+  }
+
+  public static void wtf(String prefix, Throwable e){
+    if (WXEnvironment.isApkDebugable()) {
+      wtf(prefix + getStackTrace(e));
+    }
+  }
+
+  /**
+   * 'p' for 'Performance', use {@link #WEEX_PERF_TAG}
+   */
+  public static void p(String prefix, Throwable e) {
+    if (WXEnvironment.isApkDebugable()) {
+      p(prefix + getStackTrace(e));
+    }
+  }
+
+  public static void eTag(String tag, Throwable e) {
+    if (WXEnvironment.isApkDebugable()) {
+      e(tag, getStackTrace(e));
+    }
+  }
+
+  public static String getStackTrace(@Nullable Throwable e) {
+    if (e == null) {
+      return "";
+    }
+    StringWriter sw = null;
+    PrintWriter pw = null;
+    try {
+      sw = new StringWriter();
+      pw = new PrintWriter(sw);
+      e.printStackTrace(pw);
+      pw.flush();
+      sw.flush();
+    } finally {
+      if (sw != null) {
+        try {
+          sw.close();
+        } catch (IOException e1) {
+          e1.printStackTrace();
+        }
+      }
+      if (pw != null) {
+        pw.close();
+      }
+    }
+    return sw.toString();
+  }
+
+
+
+  private static void writeConsoleLog(String level, String message) {
+    if (WXEnvironment.isApkDebugable()) {
+      try {
+        Class<?> clazz = clazzMaps.get(CLAZZ_NAME_LOG_UTIL);
+        if (clazz != null) {
+          Method m = clazz.getMethod("log", String.class, String.class);
+          m.invoke(clazz, level, message);
+        }
+      } catch (Exception e) {
+        Log.d(WEEX_TAG, "LogUtil not found!");
+      }
+    }
+  }
+
+  public static void setJsLogWatcher(JsLogWatcher watcher) {
+    if (!jsLogWatcherList.contains(watcher)) {
+      jsLogWatcherList.add(watcher);
+    }
+  }
+
+  public static void setLogWatcher(LogWatcher watcher) {
+    sLogWatcher = watcher;
+  }
+
+  public interface JsLogWatcher {
+    void onJsLog(int level, String log);
+  }
+
+  public interface LogWatcher {
+    void onLog(String level, String tag, String msg);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXMap.java b/android/sdk/src/main/java/org/apache/weex/utils/WXMap.java
new file mode 100644
index 0000000..00b2f15
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXMap.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+public class WXMap extends HashMap<String, String> implements Serializable {
+
+  public String put(String key, byte[] value) {
+    return super.put(key, new String(value));
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXReflectionUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXReflectionUtils.java
new file mode 100644
index 0000000..4c9126f
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXReflectionUtils.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.text.TextUtils;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+
+public class WXReflectionUtils {
+
+  public static Object parseArgument(Type paramClazz, Object value) {
+    if(value != null){
+      if(value.getClass() == paramClazz){
+        return  value;
+      }
+      if(paramClazz instanceof  Class){
+        if( ((Class<?>) paramClazz).isAssignableFrom(value.getClass()))   {
+          return value;
+        }
+      }
+    }
+    if (paramClazz == String.class) {
+      return value instanceof String ? value : JSON.toJSONString(value);
+    } else if (paramClazz == int.class) {
+      return value.getClass().isAssignableFrom(int.class) ? value : WXUtils.getInt(value);
+    } else if (paramClazz == long.class) {
+      return value.getClass().isAssignableFrom(long.class) ? value : WXUtils.getLong(value);
+    } else if (paramClazz == double.class) {
+      return value.getClass().isAssignableFrom(double.class) ? value : WXUtils.getDouble(value);
+    } else if (paramClazz == float.class) {
+      return value.getClass().isAssignableFrom(float.class) ? value : WXUtils.getFloat(value);
+    } else if (paramClazz == JSONArray.class && value != null && value.getClass() == JSONArray.class) {
+      return  value;
+    } else if (paramClazz == JSONObject.class && value != null && value.getClass() == JSONObject.class) {
+      return  value;
+    } else {
+      return JSON.parseObject(value instanceof String ? (String) value : JSON.toJSONString(value), paramClazz);
+    }
+  }
+
+
+  public static void setValue(Object obj, String fieldName, Object value) {
+    if (obj == null || TextUtils.isEmpty(fieldName)) {
+      return;
+    }
+
+    try {
+      // Field field = obj.getClass().getDeclaredField(fieldName);
+      Field field = getDeclaredField(obj, fieldName);
+
+      Object realValue = value;
+      if (value instanceof BigDecimal || value instanceof Number || value instanceof String) {
+        if (field.getType() == Float.class || field.getType() == float.class) {
+          realValue = Float.parseFloat(value.toString());
+        } else if (field.getType() == Double.class || field.getType() == double.class) {
+          realValue = Double.parseDouble(value.toString());
+        } else if (field.getType() == Integer.class || field.getType() == int.class) {
+          realValue = (int) Double.parseDouble(value.toString());
+        } else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
+          realValue = Boolean.valueOf(value.toString());
+        }
+      }
+
+      if (field.getType() == boolean.class || field.getType() == Boolean.class) {
+        if (value != null) {
+          realValue = Boolean.valueOf(value.toString());
+        }
+      }
+
+      setProperty(obj, field, realValue);
+    } catch (Exception e) {
+      return;
+    }
+  }
+
+  /**
+   * get field form object and it's parent
+   */
+  public static Field getDeclaredField(Object object, String fieldName) {
+    Field field = null;
+
+    Class<?> clazz = object.getClass();
+
+    for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
+      try {
+        field = clazz.getDeclaredField(fieldName);
+        return field;
+      } catch (Exception e) {
+
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Set property(field) of the specified object.
+   * @param bean The object which has the given property
+   * @param field The field to be set
+   * @param value The value to be set to the field
+   * @throws IllegalAccessException
+   * @throws InvocationTargetException
+   * @throws NoSuchMethodException
+   */
+  public static void setProperty(Object bean, Field field, Object value) throws IllegalAccessException,
+          InvocationTargetException,
+          NoSuchMethodException {
+
+    if (bean == null || field == null) {
+      return;
+    }
+
+    try {
+      field.setAccessible(true);
+      field.set(bean, value);
+    } catch (Exception e) {
+    }
+
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXResourceUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXResourceUtils.java
new file mode 100644
index 0000000..d305e3e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXResourceUtils.java
@@ -0,0 +1,451 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Shader;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.util.Pair;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * Class for parse color
+ */
+public class WXResourceUtils {
+
+  private final static Map<String, Integer> colorMap = new HashMap<>();
+  private final static int RGB_SIZE = 3;
+  private final static int RGBA_SIZE = 4;
+  private final static int HEX = 16;
+  private final static int COLOR_RANGE = 255;
+  private final static String RGB = "rgb";
+  private final static String RGBA = "rgba";
+  private final static SingleFunctionParser.FlatMapper<Integer> FUNCTIONAL_RGB_MAPPER =
+          new SingleFunctionParser.FlatMapper<Integer>() {
+            @Override
+            public Integer map(String raw) {
+              int color = WXUtils.parseUnitOrPercent(raw, COLOR_RANGE);
+              if (color < 0) {
+                color = 0;
+              } else if (color > COLOR_RANGE) {
+                color = COLOR_RANGE;
+              }
+              return color;
+            }
+          };
+
+  private final static SingleFunctionParser.NonUniformMapper<Number> FUNCTIONAL_RGBA_MAPPER =
+          new SingleFunctionParser.NonUniformMapper<Number>() {
+            @Override
+            public List<Number> map(List<String> raw) {
+              List<Number> result = new ArrayList<>(RGBA_SIZE);
+              int i, color;
+              for (i = 0; i < RGB_SIZE; i++) {
+                color = WXUtils.parseUnitOrPercent(raw.get(i), COLOR_RANGE);
+                if (color < 0) {
+                  color = 0;
+                } else if (color > COLOR_RANGE) {
+                  color = COLOR_RANGE;
+                }
+                result.add(color);
+              }
+              result.add(Float.valueOf(raw.get(i)));
+              return result;
+            }
+          };
+
+  static {
+    colorMap.put("aliceblue", 0XFFF0F8FF);
+    colorMap.put("antiquewhite", 0XFFFAEBD7);
+    colorMap.put("aqua", 0XFF00FFFF);
+    colorMap.put("aquamarine", 0XFF7FFFD4);
+    colorMap.put("azure", 0XFFF0FFFF);
+    colorMap.put("beige", 0XFFF5F5DC);
+    colorMap.put("bisque", 0XFFFFE4C4);
+    colorMap.put("black", 0XFF000000);
+    colorMap.put("blanchedalmond", 0XFFFFEBCD);
+    colorMap.put("blue", 0XFF0000FF);
+    colorMap.put("blueviolet", 0XFF8A2BE2);
+    colorMap.put("brown", 0XFFA52A2A);
+    colorMap.put("burlywood", 0XFFDEB887);
+    colorMap.put("cadetblue", 0XFF5F9EA0);
+    colorMap.put("chartreuse", 0XFF7FFF00);
+    colorMap.put("chocolate", 0XFFD2691E);
+    colorMap.put("coral", 0XFFFF7F50);
+    colorMap.put("cornflowerblue", 0XFF6495ED);
+    colorMap.put("cornsilk", 0XFFFFF8DC);
+    colorMap.put("crimson", 0XFFDC143C);
+    colorMap.put("cyan", 0XFF00FFFF);
+    colorMap.put("darkblue", 0XFF00008B);
+    colorMap.put("darkcyan", 0XFF008B8B);
+    colorMap.put("darkgoldenrod", 0XFFB8860B);
+    colorMap.put("darkgray", 0XFFA9A9A9);
+    colorMap.put("darkgreen", 0XFF006400);
+    colorMap.put("darkkhaki", 0XFFBDB76B);
+    colorMap.put("darkmagenta", 0XFF8B008B);
+    colorMap.put("darkolivegreen", 0XFF556B2F);
+    colorMap.put("darkorange", 0XFFFF8C00);
+    colorMap.put("darkorchid", 0XFF9932CC);
+    colorMap.put("darkred", 0XFF8B0000);
+    colorMap.put("darksalmon", 0XFFE9967A);
+    colorMap.put("darkseagreen", 0XFF8FBC8F);
+    colorMap.put("darkslateblue", 0XFF483D8B);
+    colorMap.put("darkslategray", 0XFF2F4F4F);
+    colorMap.put("darkslategrey", 0XFF2F4F4F);
+    colorMap.put("darkturquoise", 0XFF00CED1);
+    colorMap.put("darkviolet", 0XFF9400D3);
+    colorMap.put("deeppink", 0XFFFF1493);
+    colorMap.put("deepskyblue", 0XFF00BFFF);
+    colorMap.put("dimgray", 0XFF696969);
+    colorMap.put("dimgrey", 0XFF696969);
+    colorMap.put("dodgerblue", 0XFF1E90FF);
+    colorMap.put("firebrick", 0XFFB22222);
+    colorMap.put("floralwhite", 0XFFFFFAF0);
+    colorMap.put("forestgreen", 0XFF228B22);
+    colorMap.put("fuchsia", 0XFFFF00FF);
+    colorMap.put("gainsboro", 0XFFDCDCDC);
+    colorMap.put("ghostwhite", 0XFFF8F8FF);
+    colorMap.put("gold", 0XFFFFD700);
+    colorMap.put("goldenrod", 0XFFDAA520);
+    colorMap.put("gray", 0XFF808080);
+    colorMap.put("grey", 0XFF808080);
+    colorMap.put("green", 0XFF008000);
+    colorMap.put("greenyellow", 0XFFADFF2F);
+    colorMap.put("honeydew", 0XFFF0FFF0);
+    colorMap.put("hotpink", 0XFFFF69B4);
+    colorMap.put("indianred", 0XFFCD5C5C);
+    colorMap.put("indigo", 0XFF4B0082);
+    colorMap.put("ivory", 0XFFFFFFF0);
+    colorMap.put("khaki", 0XFFF0E68C);
+    colorMap.put("lavender", 0XFFE6E6FA);
+    colorMap.put("lavenderblush", 0XFFFFF0F5);
+    colorMap.put("lawngreen", 0XFF7CFC00);
+    colorMap.put("lemonchiffon", 0XFFFFFACD);
+    colorMap.put("lightblue", 0XFFADD8E6);
+    colorMap.put("lightcoral", 0XFFF08080);
+    colorMap.put("lightcyan", 0XFFE0FFFF);
+    colorMap.put("lightgoldenrodyellow", 0XFFFAFAD2);
+    colorMap.put("lightgray", 0XFFD3D3D3);
+    colorMap.put("lightgrey", 0XFFD3D3D3);
+    colorMap.put("lightgreen", 0XFF90EE90);
+    colorMap.put("lightpink", 0XFFFFB6C1);
+    colorMap.put("lightsalmon", 0XFFFFA07A);
+    colorMap.put("lightseagreen", 0XFF20B2AA);
+    colorMap.put("lightskyblue", 0XFF87CEFA);
+    colorMap.put("lightslategray", 0XFF778899);
+    colorMap.put("lightslategrey", 0XFF778899);
+    colorMap.put("lightsteelblue", 0XFFB0C4DE);
+    colorMap.put("lightyellow", 0XFFFFFFE0);
+    colorMap.put("lime", 0XFF00FF00);
+    colorMap.put("limegreen", 0XFF32CD32);
+    colorMap.put("linen", 0XFFFAF0E6);
+    colorMap.put("magenta", 0XFFFF00FF);
+    colorMap.put("maroon", 0XFF800000);
+    colorMap.put("mediumaquamarine", 0XFF66CDAA);
+    colorMap.put("mediumblue", 0XFF0000CD);
+    colorMap.put("mediumorchid", 0XFFBA55D3);
+    colorMap.put("mediumpurple", 0XFF9370DB);
+    colorMap.put("mediumseagreen", 0XFF3CB371);
+    colorMap.put("mediumslateblue", 0XFF7B68EE);
+    colorMap.put("mediumspringgreen", 0XFF00FA9A);
+    colorMap.put("mediumturquoise", 0XFF48D1CC);
+    colorMap.put("mediumvioletred", 0XFFC71585);
+    colorMap.put("midnightblue", 0XFF191970);
+    colorMap.put("mintcream", 0XFFF5FFFA);
+    colorMap.put("mistyrose", 0XFFFFE4E1);
+    colorMap.put("moccasin", 0XFFFFE4B5);
+    colorMap.put("navajowhite", 0XFFFFDEAD);
+    colorMap.put("navy", 0XFF000080);
+    colorMap.put("oldlace", 0XFFFDF5E6);
+    colorMap.put("olive", 0XFF808000);
+    colorMap.put("olivedrab", 0XFF6B8E23);
+    colorMap.put("orange", 0XFFFFA500);
+    colorMap.put("orangered", 0XFFFF4500);
+    colorMap.put("orchid", 0XFFDA70D6);
+    colorMap.put("palegoldenrod", 0XFFEEE8AA);
+    colorMap.put("palegreen", 0XFF98FB98);
+    colorMap.put("paleturquoise", 0XFFAFEEEE);
+    colorMap.put("palevioletred", 0XFFDB7093);
+    colorMap.put("papayawhip", 0XFFFFEFD5);
+    colorMap.put("peachpuff", 0XFFFFDAB9);
+    colorMap.put("peru", 0XFFCD853F);
+    colorMap.put("pink", 0XFFFFC0CB);
+    colorMap.put("plum", 0XFFDDA0DD);
+    colorMap.put("powderblue", 0XFFB0E0E6);
+    colorMap.put("purple", 0XFF800080);
+    colorMap.put("rebeccapurple", 0XFF663399);
+    colorMap.put("red", 0XFFFF0000);
+    colorMap.put("rosybrown", 0XFFBC8F8F);
+    colorMap.put("royalblue", 0XFF4169E1);
+    colorMap.put("saddlebrown", 0XFF8B4513);
+    colorMap.put("salmon", 0XFFFA8072);
+    colorMap.put("sandybrown", 0XFFF4A460);
+    colorMap.put("seagreen", 0XFF2E8B57);
+    colorMap.put("seashell", 0XFFFFF5EE);
+    colorMap.put("sienna", 0XFFA0522D);
+    colorMap.put("silver", 0XFFC0C0C0);
+    colorMap.put("skyblue", 0XFF87CEEB);
+    colorMap.put("slateblue", 0XFF6A5ACD);
+    colorMap.put("slategray", 0XFF708090);
+    colorMap.put("slategrey", 0XFF708090);
+    colorMap.put("snow", 0XFFFFFAFA);
+    colorMap.put("springgreen", 0XFF00FF7F);
+    colorMap.put("steelblue", 0XFF4682B4);
+    colorMap.put("tan", 0XFFD2B48C);
+    colorMap.put("teal", 0XFF008080);
+    colorMap.put("thistle", 0XFFD8BFD8);
+    colorMap.put("tomato", 0XFFFF6347);
+    colorMap.put("turquoise", 0XFF40E0D0);
+    colorMap.put("violet", 0XFFEE82EE);
+    colorMap.put("wheat", 0XFFF5DEB3);
+    colorMap.put("white", 0XFFFFFFFF);
+    colorMap.put("whitesmoke", 0XFFF5F5F5);
+    colorMap.put("yellow", 0XFFFFFF00);
+    colorMap.put("yellowgreen", 0XFF9ACD32);
+    colorMap.put("transparent", 0x00000000);
+  }
+
+  public static int getColor(String color) {
+    return getColor(color, Integer.MIN_VALUE);
+  }
+
+  public static int getColor(String color, int defaultColor) {
+    if (TextUtils.isEmpty(color)) {
+      return defaultColor;
+    }
+    color = color.trim(); //remove non visible codes
+
+    Integer cache = WXUtils.sCache.get(color);
+    if(cache!=null){
+      return cache;
+    }
+    else {
+      int resultColor = defaultColor;
+      Pair<Boolean, Integer> result;
+      ColorConvertHandler[] handlers = ColorConvertHandler.values();
+      for (ColorConvertHandler handler : handlers) {
+        try {
+          result = handler.handle(color);
+          if (result.first) {
+            resultColor = result.second;
+            WXUtils.sCache.put(color, resultColor);
+            break;
+          }
+        } catch (RuntimeException e) {
+          WXLogUtils.v("Color_Parser", WXLogUtils.getStackTrace(e));
+        }
+      }
+      return resultColor;
+    }
+  }
+
+  /**
+   * Assembly gradients
+   * @param image gradient values contains direction、colors
+   * @param width component width
+   * @param height component height
+   * @return gradient shader
+   */
+  public static Shader getShader(String image, float width, float height) {
+    List<String> valueList = parseGradientValues(image);
+    if (valueList != null && valueList.size() == 3) {
+      float[] points = parseGradientDirection(valueList.get(0), width, height);
+      Shader shader = new LinearGradient(points[0], points[1],
+              points[2], points[3],
+              getColor(valueList.get(1), Color.WHITE), getColor(valueList.get(2), Color.WHITE),
+              Shader.TileMode.CLAMP);
+      return shader;
+    }
+    return null;
+  }
+
+  /**
+   * parse gradient values contains direction、colors
+   * @param image gradient values
+   * @return split values by comma
+   */
+  @NonNull
+  private static List<String> parseGradientValues(String image) {
+    if (TextUtils.isEmpty(image)) {
+      return null;
+    }
+    image.trim();
+    if(image.startsWith("linear-gradient")){
+      String valueStr = image.substring(image.indexOf("(") + 1, image.lastIndexOf(")"));
+      StringTokenizer tokenizer = new StringTokenizer(valueStr, ",");
+      List<String> values = new ArrayList<>();
+      String temp = null;
+      while (tokenizer.hasMoreTokens()) {
+        String token = tokenizer.nextToken();
+        if (token.contains("(")) {
+          temp = token + ",";
+          continue;
+        }
+        if (token.contains(")")) {
+          temp += token;
+          values.add(temp);
+          temp = null;
+          continue;
+        }
+        if (temp != null) {
+          temp += (token + ",");
+          continue;
+        }
+        values.add(token);
+      }
+      return values;
+    }
+    return null;
+  }
+
+  /**
+   * parse gradient direction
+   * @param direction gradient direction
+   * @param width component width
+   * @param height component height
+   * @return gradient points
+   */
+  private static float[] parseGradientDirection(String direction, float width, float height) {
+    int x1 = 0, y1 = 1, x2 = 2, y2 = 3;
+    float[] points = {0, 0, 0, 0};
+
+    if (!TextUtils.isEmpty(direction)) {
+      direction = direction.replaceAll("\\s*", "").toLowerCase(Locale.ROOT);
+    }
+
+    switch (direction) {
+      //to right
+      case "toright":
+        points[x2] = width;
+        break;
+      //to left
+      case "toleft":
+        points[x1] = width;
+        break;
+      //to bottom
+      case "tobottom":
+        points[y2] = height;
+        break;
+      //to top
+      case "totop":
+        points[y1] = height;
+        break;
+      //to bottom right
+      case "tobottomright":
+        points[x2] = width;
+        points[y2] = height;
+        break;
+      //to top left
+      case "totopleft":
+        points[x1] = width;
+        points[y1] = height;
+        break;
+    }
+    return points;
+  }
+
+  public static boolean isNamedColor(String name) {
+    return colorMap.containsKey(name);
+  }
+
+  enum ColorConvertHandler {
+    NAMED_COLOR_HANDLER {
+      @Override
+      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
+        if (colorMap.containsKey(rawColor)) {
+          return new Pair<>(Boolean.TRUE, colorMap.get(rawColor));
+        } else {
+          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
+        }
+      }
+    },
+    RGB_HANDLER {
+      @Override
+      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
+        if (rawColor.length() == 4) {
+          //#eee, #333
+          int r, g, b;
+          r = Integer.parseInt(rawColor.substring(1, 2), HEX);
+          g = Integer.parseInt(rawColor.substring(2, 3), HEX);
+          b = Integer.parseInt(rawColor.substring(3, 4), HEX);
+          return new Pair<>(Boolean.TRUE, Color.rgb(r + (r << 4), g + (g << 4), b + (b << 4)));
+        } else if (rawColor.length() == 7 || rawColor.length() == 9) {
+          //#eeeeee, #333333
+          return new Pair<>(Boolean.TRUE, Color.parseColor(rawColor));
+        } else {
+          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
+        }
+      }
+    },
+    FUNCTIONAL_RGB_HANDLER {
+      @Override
+      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
+        SingleFunctionParser<Integer> functionParser = new SingleFunctionParser<>(rawColor, FUNCTIONAL_RGB_MAPPER);
+        List<Integer> rgb = functionParser.parse(RGB);
+        if (null != rgb && rgb.size() == RGB_SIZE) {
+          return new Pair<>(Boolean.TRUE, Color.rgb(rgb.get(0), rgb.get(1), rgb.get(2)));
+        } else {
+          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
+        }
+      }
+    },
+
+    FUNCTIONAL_RGBA_HANDLER {
+      @Override
+      @NonNull Pair<Boolean, Integer> handle(String rawColor) {
+        SingleFunctionParser<Number> functionParser = new SingleFunctionParser<>(rawColor, FUNCTIONAL_RGBA_MAPPER);
+        List<Number> rgba = functionParser.parse(RGBA);
+        if (rgba.size() == RGBA_SIZE) {
+          return new Pair<>(Boolean.TRUE, Color.argb(
+                  parseAlpha(rgba.get(3).floatValue()),
+                  rgba.get(0).intValue(),
+                  rgba.get(1).intValue(),
+                  rgba.get(2).intValue()));
+        } else {
+          return new Pair<>(Boolean.FALSE, Color.TRANSPARENT);
+        }
+      }
+    };
+
+    /**
+     * Parse color to #RRGGBB or #AARRGGBB. The parsing algorithm depends on sub-class.
+     *
+     * @param rawColor color, maybe functional RGB(RGBA), #RGB, keywords color or transparent
+     * @return #RRGGBB or #AARRGGBB
+     */
+    @NonNull abstract Pair<Boolean, Integer> handle(String rawColor);
+
+    /**
+     * Parse alpha gradient of color from range 0-1 to range 0-255
+     *
+     * @param alpha the alpha value, in range 0-1
+     * @return the alpha value, in range 0-255
+     */
+    private static int parseAlpha(float alpha) {
+      return (int) (alpha * COLOR_RANGE);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXSoInstallMgrSdk.java b/android/sdk/src/main/java/org/apache/weex/utils/WXSoInstallMgrSdk.java
new file mode 100644
index 0000000..e5140a7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXSoInstallMgrSdk.java
@@ -0,0 +1,607 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.annotation.SuppressLint;
+import android.app.Application;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.text.TextUtils;
+import org.apache.weex.IWXStatisticsListener;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.adapter.IWXSoLoaderAdapter;
+import org.apache.weex.adapter.IWXUserTrackAdapter;
+import org.apache.weex.common.WXErrorCode;
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+
+/**
+ * Utility class for managing so library, including load native library and version management.
+ * <ol>
+ *   <li>Load library<br>
+ *     It Will try to use {@link System#loadLibrary(String)} to load native library. If it successes,
+ *     the Android Framework will be responsible for managing library and library version.
+ *     If it fails in case of some ceratin armebi-v7a architecture device, it will try to extract
+ *     native library from apk and copy it the data directory of the app. Then load it using
+ *     {@link System#load(String)}.
+ *     </li>
+ *  <li>
+ *       Version control for extracting native library from apk.
+ *  </li>
+ * </ol>
+ */
+public class WXSoInstallMgrSdk {
+
+  final static String LOGTAG = "INIT_SO";
+  //below is the CPU string types
+  private final static String ARMEABI = "armeabi"; //default
+  private final static String X86 = "x86";
+  private final static String MIPS = "mips";
+  private final static String STARTUPSO = "/libweexjsb.so";
+  private final static String STARTUPSOANDROID15 = "/libweexjst.so";
+
+  static Application mContext = null;
+  private static IWXSoLoaderAdapter mSoLoader = null;
+  private static IWXStatisticsListener mStatisticsListener = null;
+
+  private static String mAbi = null;
+
+  public static void init(Application c,
+                          IWXSoLoaderAdapter loader,
+                          IWXStatisticsListener listener) {
+    mContext = c;
+    mSoLoader = loader;
+    mStatisticsListener = listener;
+  }
+
+  public static boolean isX86(){
+    String cpuType = _cpuType();
+    return cpuType.equalsIgnoreCase(X86);
+  }
+
+  public static boolean isCPUSupport(){
+    String cpuType = _cpuType();
+    return !cpuType.equalsIgnoreCase(MIPS);
+  }
+
+  /**
+   * Load so library.
+   *
+   * If a library loader adapter exists, use this adapter to load library,
+   * otherwise use {@link System#loadLibrary(String)} to load library.
+   * If failed to load library, try to extract the so library and load it
+   * from arembi in the .apk
+   *
+   * @param libName library name, like webp, not necessary to be libwep.so
+   * @param version the version of the so library
+   */
+  public static boolean initSo(String libName, int version, IWXUserTrackAdapter utAdapter) {
+    String cpuType = _cpuType();
+    if (cpuType.equalsIgnoreCase(MIPS) ) {
+      WXExceptionUtils.commitCriticalExceptionRT(null,
+              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
+              "initSo", "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for android cpuType is MIPS",
+              null);
+      return false;
+    }
+
+    // copy startup so
+    if (WXEnvironment.CORE_SO_NAME.equals(libName)) {
+      copyStartUpSo();
+    }
+
+
+    boolean InitSuc = false;
+      try {
+        // If a library loader adapter exists, use this adapter to load library
+        // instead of System.loadLibrary.
+        if (mSoLoader != null) {
+          mSoLoader.doLoadLibrary("c++_shared");
+        } else {
+          System.loadLibrary("c++_shared");
+        }
+      } catch (Exception | Error e) {
+        WXExceptionUtils.commitCriticalExceptionRT(null,
+                WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
+                "initSo",
+                        "load c++_shared failed Detail Error is: " +e.getMessage(),
+                null);
+
+        if(WXEnvironment.isApkDebugable()) {
+          throw e;
+        }
+      }
+
+      /**
+       * Load library with {@link System#loadLibrary(String)}
+       */
+      try {
+        // If a library loader adapter exists, use this adapter to load library
+        // instead of System.loadLibrary.
+        if (mSoLoader != null) {
+          mSoLoader.doLoadLibrary(libName);
+        } else {
+          System.loadLibrary(libName);
+        }
+
+        InitSuc = true;
+      } catch (Exception | Error e2) {
+        if (cpuType.contains(ARMEABI) || cpuType.contains(X86)) {
+          WXExceptionUtils.commitCriticalExceptionRT(null,
+                  WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
+                  "initSo", libName + "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for android cpuType is " +cpuType +
+                          "\n Detail Error is: " +e2.getMessage(),
+                  null);
+        }
+
+        if(WXEnvironment.isApkDebugable()) {
+          throw e2;
+        }
+        InitSuc = false;
+      }
+
+//      try {
+
+//        if (!InitSuc) {
+//
+//          //File extracted from apk already exists.
+//          if (isExist(libName, version)) {
+//            boolean res = _loadUnzipSo(libName, version, utAdapter);
+//            if (res) {
+//              return res;
+//            } else {
+//              //Delete the corrupt so library, and extract it again.
+//              removeSoIfExit(libName, version);
+//            }
+//          }
+//
+//          //Fail for loading file from libs, extract so library from so and load it.
+//          if (cpuType.equalsIgnoreCase(MIPS)) {
+//            return false;
+//          } else {
+//            try {
+//              InitSuc = unZipSelectedFiles(libName, version, utAdapter);
+//            } catch (IOException e2) {
+//              e2.printStackTrace();
+//            }
+//          }
+//
+//        }
+//      } catch (Exception | Error e) {
+//        InitSuc = false;
+//        e.printStackTrace();
+//      }
+  //  }
+    return InitSuc;
+  }
+
+  private static File _desSoCopyFile(String soName) {
+    String cpuType = _cpuType();
+    String copyPath = WXEnvironment.copySoDesDir();
+    if (TextUtils.isEmpty(copyPath)) {
+      return null;
+    }
+    File desDir = new File(copyPath, soName + "/" + cpuType);
+    return desDir;
+  }
+
+  /**
+   * copyStartUpSo
+   */
+  @SuppressLint("SdCardPath")
+  public static void copyStartUpSo() {
+    try {
+      // copy libjsb.so to cache/weex/jsb/cputype
+      String pkgName = WXEnvironment.getApplication().getPackageName();
+      String cacheFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
+
+      // cp weexjsb any way
+      // if android api < 16 copy libweexjst.so else copy libweexjsb.so
+      boolean pieSupport = true;
+      File newfile;
+      String startSoName = WXEnvironment.CORE_JSB_SO_NAME;
+      String startSoPath = STARTUPSO;
+      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+        pieSupport = false;
+        startSoName = WXEnvironment.CORE_JST_SO_NAME;
+        startSoPath = STARTUPSOANDROID15;
+      }
+
+      final File copyPath = _desSoCopyFile(startSoName);
+      if(!copyPath.exists()) {
+        copyPath.mkdirs();
+      }
+      newfile = new File(copyPath, startSoPath);
+      WXEnvironment.CORE_JSB_SO_PATH = newfile.getAbsolutePath();
+      String jsb = WXEnvironment.getDefaultSettingValue(startSoName, "-1");
+      if(newfile.exists() && TextUtils.equals(WXEnvironment.getAppVersionName(), jsb)) {
+        // no update so skip copy
+        return;
+      }
+
+      String path = "/data/data/" + pkgName + "/lib";
+      if (cacheFile != null && cacheFile.indexOf("/cache") > 0) {
+        path = cacheFile.replace("/cache", "/lib");
+      }
+      File oldfile = null;
+      if (pieSupport) {
+        oldfile = new File(path, STARTUPSO);
+      } else {
+        oldfile = new File(path , STARTUPSOANDROID15);
+      }
+
+
+      if (!oldfile.exists()) {
+        try {
+          String weexjsb = ((PathClassLoader) (WXSoInstallMgrSdk.class.getClassLoader())).findLibrary(startSoName);
+          oldfile = new File(weexjsb);
+        } catch (Throwable throwable) {
+          // do nothing
+        }
+      }
+
+
+      if(!oldfile.exists()) {
+        WXEnvironment.extractSo();
+        oldfile = new File(copyPath, STARTUPSO);
+      }
+
+      if (oldfile.exists()) {
+        WXFileUtils.copyFile(oldfile, newfile);
+      }
+      WXEnvironment.writeDefaultSettingsValue(startSoName, WXEnvironment.getAppVersionName());
+    } catch (Throwable e) {
+      e.printStackTrace();
+    }
+  }
+
+  public static void copyJssRuntimeSo(){
+    boolean tryUseRunTimeApi = WXUtils.checkGreyConfig("wxapm","use_runtime_api","0");
+    WXLogUtils.e("weex", "tryUseRunTimeApi ? "+ tryUseRunTimeApi);
+    if (!tryUseRunTimeApi){
+      return;
+    }
+    try {
+      WXLogUtils.e("weex", "copyJssRuntimeSo: ");
+      File toPath = _desSoCopyFile(WXEnvironment.CORE_JSS_SO_NAME);
+      if(!toPath.exists()) {
+        toPath.mkdirs();
+      }
+      File targetFile = new File(toPath,"libweexjss.so");
+
+      /** 1. check so and versionCode. if update, then rm old jss.so(runtime) in pkg/libs, and copy new so from apk **/
+      String keyVersionCode = "app_version_code_weex";
+      String defaultSettingValue = WXEnvironment.getDefaultSettingValue(keyVersionCode, "-1");
+
+
+      if (targetFile.exists()){
+        if (!TextUtils.equals(WXEnvironment.getAppVersionName(),defaultSettingValue)){
+          targetFile.delete();
+        }else {
+          WXEnvironment.CORE_JSS_SO_PATH= targetFile.getAbsolutePath();
+          WXEnvironment.sUseRunTimeApi = true;
+          WXLogUtils.e("weex", "copyJssRuntimeSo exist:  return");
+          return;
+        }
+      }
+      /** 2. copy jss(runtime) so **/
+      String fromPath =  ((PathClassLoader) (WXSoInstallMgrSdk.class.getClassLoader())).findLibrary("weexjssr");
+      if (TextUtils.isEmpty(fromPath)){
+        return;
+      }
+      targetFile.createNewFile();
+      WXFileUtils.copyFileWithException(new File(fromPath),targetFile);
+      /**3. update flag **/
+      WXEnvironment.CORE_JSS_SO_PATH= targetFile.getAbsolutePath();
+      WXEnvironment.writeDefaultSettingsValue(keyVersionCode,WXEnvironment.getAppVersionName());
+      WXEnvironment.sUseRunTimeApi = true;
+      WXLogUtils.e("weex", "copyJssRuntimeSo: cp end and return ");
+    }catch (Throwable e){
+      e.printStackTrace();
+      WXEnvironment.sUseRunTimeApi = false;
+      WXLogUtils.e("weex", "copyJssRuntimeSo:  exception" + e);
+    }
+  }
+
+  private static String _getFieldReflectively(Build build, String fieldName) {
+    try {
+      final Field field = Build.class.getField(fieldName);
+      return field.get(build).toString();
+    } catch (Exception ex) {
+      return "Unknown";
+    }
+  }
+
+  private static String _cpuType() {
+    if(TextUtils.isEmpty(mAbi)) {
+      try {
+        mAbi = Build.CPU_ABI;
+      }catch (Throwable e){
+        e.printStackTrace();
+        mAbi = ARMEABI;
+      }
+      if (TextUtils.isEmpty(mAbi)){
+        mAbi = ARMEABI;
+      }
+      mAbi = mAbi.toLowerCase(Locale.ROOT);
+    }
+    return mAbi;
+  }
+
+  /**
+   *
+   * @param libName lib name
+   * @param size  the right size of lib
+   * @return true for valid  ; false for InValid
+   */
+  static boolean checkSoIsValid(String libName, long size) {
+    Context context = mContext;
+    if (null == context) {
+      return false;
+    }
+    try{
+      long start=System.currentTimeMillis();
+      if(WXSoInstallMgrSdk.class.getClassLoader() instanceof PathClassLoader ) {
+
+        String path = ((PathClassLoader) (WXSoInstallMgrSdk.class.getClassLoader())).findLibrary(libName);
+        if(TextUtils.isEmpty(path) ){
+          return false;
+        }
+        File file = new File(path);
+
+        if (!file.exists() || size == file.length()) {
+          WXLogUtils.w("weex so size check path :" + path+"   "+(System.currentTimeMillis() - start));
+          return true;
+        } else {
+          return false;
+        }
+      }
+    }catch(Throwable e ){
+      WXExceptionUtils.commitCriticalExceptionRT(null,
+              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
+              "checkSoIsValid", "[WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT] for " +
+                      "weex so size check fail exception :"+e.getMessage(),
+              null);
+      WXLogUtils.e("weex so size check fail exception :"+e.getMessage());
+    }
+
+    return true;
+  }
+
+  /**
+   * Concatenate the path of the so library, including directory.
+   * @param libName the raw name of the lib
+   * @param version the version of the so library
+   * @return the path of the so library
+   */
+  @SuppressLint("SdCardPath")
+  static String _targetSoFile(String libName, int version) {
+    Context context = mContext;
+    if (null == context) {
+      return "";
+    }
+
+    String path = "/data/data/" + context.getPackageName() + "/files";
+
+    File f = context.getFilesDir();
+    if (f != null) {
+      path = f.getPath();
+    }
+    return path + "/lib" + libName + "bk" + version + ".so";
+
+  }
+
+  /**
+   * Remove the so library if it had been extracted.
+   * @param libName
+   * @param version
+   */
+  static void removeSoIfExit(String libName, int version) {
+
+    String file = _targetSoFile(libName, version);
+    File a = new File(file);
+    if (a.exists()) {
+      a.delete();
+    }
+
+  }
+
+  /**
+   * Tell whether the so is extracted.
+   */
+  static boolean isExist(String libName, int version) {
+
+    String file = _targetSoFile(libName, version);
+    File a = new File(file);
+    return a.exists();
+
+  }
+
+
+  /**
+   * Load .so library
+   */
+  @SuppressLint("UnsafeDynamicallyLoadedCode")
+  static boolean _loadUnzipSo(String libName,
+                              int version,
+                              IWXUserTrackAdapter utAdapter) {
+    boolean initSuc = false;
+    try {
+      if (isExist(libName, version)) {
+        // If a library loader adapter exists, use this adapter to load library
+        // instead of System.load.
+        if (mSoLoader != null) {
+          mSoLoader.doLoad(_targetSoFile(libName, version));
+        } else {
+          System.load(_targetSoFile(libName, version));
+        }
+      }
+      initSuc = true;
+    } catch (Throwable e) {
+      initSuc = false;
+      WXExceptionUtils.commitCriticalExceptionRT(null,
+              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT,
+              "_loadUnzipSo", "[WX_KEY_EXCEPTION_SDK_INIT_WX_ERR_COPY_FROM_APK] " +
+                      "\n Detail Msg is : " +  e.getMessage(),
+              null);
+      WXLogUtils.e("", e);
+    }
+    return initSuc;
+  }
+
+  static boolean unZipSelectedFiles(String libName,
+                                    int version,
+                                    IWXUserTrackAdapter utAdapter) throws ZipException, IOException {
+    String sourcePath = "lib/armeabi/lib" + libName + ".so";
+
+    String zipPath = "";
+    Context context = mContext;
+    if (context == null) {
+      return false;
+    }
+
+    ApplicationInfo aInfo = context.getApplicationInfo();
+    if (null != aInfo) {
+      zipPath = aInfo.sourceDir;
+    }
+
+    ZipFile zf;
+    zf = new ZipFile(zipPath);
+    try {
+
+      for (Enumeration<?> entries = zf.entries(); entries.hasMoreElements(); ) {
+        ZipEntry entry = ((ZipEntry) entries.nextElement());
+        if (entry.getName().startsWith(sourcePath)) {
+
+          InputStream in = null;
+          FileOutputStream os = null;
+          FileChannel channel = null;
+          int total = 0;
+          try {
+
+            //Make sure the old library is deleted.
+            removeSoIfExit(libName, version);
+
+            //Copy file
+            in = zf.getInputStream(entry);
+            os = context.openFileOutput("lib" + libName + "bk" + version + ".so",
+                    Context.MODE_PRIVATE);
+            channel = os.getChannel();
+
+            byte[] buffers = new byte[1024];
+            int realLength;
+
+            while ((realLength = in.read(buffers)) > 0) {
+              //os.write(buffers);
+              channel.write(ByteBuffer.wrap(buffers, 0, realLength));
+              total += realLength;
+
+            }
+          } finally {
+            if (in != null) {
+              try {
+                in.close();
+              } catch (Exception e) {
+                e.printStackTrace();
+              }
+            }
+
+            if (channel != null) {
+              try {
+                channel.close();
+              } catch (Exception e) {
+                e.printStackTrace();
+              }
+            }
+
+            if (os != null) {
+              try {
+                os.close();
+              } catch (Exception e) {
+                e.printStackTrace();
+              }
+            }
+
+            if (zf != null) {
+              zf.close();
+              zf = null;
+            }
+          }
+
+          if (total > 0) {
+            return _loadUnzipSo(libName, version, utAdapter);
+          } else {
+            return false;
+          }
+        }
+      }
+    } catch (java.io.IOException e) {
+      e.printStackTrace();
+      WXExceptionUtils.commitCriticalExceptionRT(null,
+              WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT_CPU_NOT_SUPPORT,
+              "unZipSelectedFiles", "[WX_KEY_EXCEPTION_SDK_INIT_unZipSelectedFiles] " +
+                      "\n Detail msg is: " + e.getMessage(),
+              null);
+
+    } finally {
+
+      if (zf != null) {
+        zf.close();
+        zf = null;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Using {@Code WXExceptionUtils.commitCriticalExceptionRT}  insted
+   */
+//  static void commit(IWXUserTrackAdapter utAdapter, String errCode, String errMsg) {
+//    if (mStatisticsListener != null) {
+//      mStatisticsListener.onException("0", errCode, errMsg);
+//    }
+//
+//    if (utAdapter == null) {
+//      return;
+//    }
+//    if (errCode != null && errMsg != null) {
+//      WXPerformance p = new WXPerformance();
+//      p.errCode = errCode;
+//      p.errMsg = errMsg;
+//      utAdapter.commit(null, null, WXEnvironment.ENVIRONMENT, p, null);
+//    } else {
+//      utAdapter.commit(null, null, WXEnvironment.ENVIRONMENT, null, null);
+//
+//    }
+//  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXUtils.java
new file mode 100644
index 0000000..a06d47e
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXUtils.java
@@ -0,0 +1,597 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.support.annotation.Nullable;
+import android.support.v4.util.LruCache;
+import android.text.TextUtils;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.adapter.IWXConfigAdapter;
+import org.apache.weex.common.Constants;
+
+public class WXUtils {
+
+  final static LruCache<String, Integer> sCache = new LruCache<>(64);
+  public static final char PERCENT = '%';
+  private static final int HUNDRED =100;
+  /**
+   * Tell whether current thread is UI(main) thread.
+   * @return true for UI(main) thread
+   */
+  public static boolean isUiThread() {
+    return Thread.currentThread().getId() == Looper.getMainLooper().getThread().getId();
+  }
+
+  public static boolean isUndefined(float value) {
+    return Float.isNaN(value);
+  }
+
+
+  public static float getFloatByViewport(Object value, int viewport) {
+    if (value == null) {
+      return Float.NaN;
+    }
+    String temp = value.toString().trim();
+    if (Constants.Name.AUTO.equals(temp)
+            || Constants.Name.UNDEFINED.equals(temp)
+            || TextUtils.isEmpty(temp)) {
+      WXLogUtils.e("Argument Warning ! value is " + temp + "And default Value:" + Float.NaN);
+      return Float.NaN;
+    }
+
+    if (temp.endsWith("wx")) {
+      try {
+        return transferWx(temp, viewport);
+      } catch (NumberFormatException e) {
+        WXLogUtils.e("Argument format error! value is " + value, e);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    } else if (temp.endsWith("px")) {
+      try {
+        temp = temp.substring(0, temp.indexOf("px"));
+        return Float.parseFloat(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    } else {
+      try {
+        return Float.parseFloat(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }
+    return Float.NaN;
+  }
+
+  public static float getFloat(Object value) {
+    return getFloat(value, Float.NaN);
+  }
+
+  public static Float getFloat(Object value, @Nullable Float df) {
+    if (value == null) {
+      return df;
+    }
+
+    String temp = value.toString().trim();
+    if(Constants.Name.AUTO.equals(temp)
+            || Constants.Name.UNDEFINED.equals(temp)
+            || TextUtils.isEmpty(temp)){
+      WXLogUtils.e("Argument Warning ! value is " + temp + "And default Value:"+Float.NaN);
+      return df;
+    }
+    if (temp.endsWith("wx")) {
+      try {
+        return transferWx(temp, 750);
+      } catch (NumberFormatException e) {
+        WXLogUtils.e("Argument format error! value is " + value, e);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }else if (temp.endsWith("px")) {
+      try {
+        temp = temp.substring(0, temp.indexOf("px"));
+        return Float.parseFloat(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }else {
+      try {
+        return Float.parseFloat(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }
+    return df;
+  }
+
+  private static float transferWx(String stringWithWXPostfix, int viewport) {
+    if(null == stringWithWXPostfix) {
+      return 0;
+    }
+    String temp = stringWithWXPostfix;
+    if(stringWithWXPostfix.endsWith("wx")) {
+      temp = stringWithWXPostfix.substring(0, stringWithWXPostfix.indexOf("wx"));
+    }
+    Float f = Float.parseFloat(temp);
+    float density = WXEnvironment.sApplication.getResources().getDisplayMetrics().density;
+    return density * f * viewport / WXViewUtils.getScreenWidth();
+  }
+
+  public static float fastGetFloat(String raw, int precision){
+    if(!TextUtils.isEmpty(raw)){
+      boolean positive=true;
+      int loc=0;
+      if(raw.charAt(0)=='-'){
+        positive=false;
+        loc++;
+      }
+      else if(raw.charAt(0)=='+'){
+        loc++;
+      }
+
+      char digit;
+      float result=0;
+      while (loc<raw.length() && (digit=raw.charAt(loc))>='0'&&digit<='9'){
+        result=result*10+digit-'0';
+        loc++;
+      }
+
+      if(loc<raw.length()){
+        if(raw.charAt(loc)=='.'){
+          loc++;
+          int remainderLength=10;
+          int counter=0;
+          while(loc<raw.length() &&
+                  counter<precision &&
+                  ((digit=raw.charAt(loc))>='0'&& digit<='9')){
+            result+=(digit-'0')/(float)remainderLength;
+            remainderLength*=10;
+            loc++;
+            counter++;
+          }
+        }
+        else{
+          // throw new NumberFormatException("Illegal separator");
+        }
+      }
+
+      if(!positive)
+        result*=-1;
+      return result;
+    }
+    return 0;
+    // throw new NumberFormatException("NullNumber");
+  }
+
+  /**
+   * Parse string representation of float. This method intend to be faster than
+   * {@link Float#parseFloat(String)}, but less accuracy.
+   * @param raw
+   * @return
+   */
+  public static float fastGetFloat(String raw){
+    return fastGetFloat(raw, Integer.MAX_VALUE);
+  }
+
+  public static int parseInt(String value) {
+    try {
+      if (!TextUtils.isEmpty(value) && !value.contains(".")) {
+        return Integer.parseInt(value);
+      }
+    } catch (NumberFormatException e) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(WXLogUtils.getStackTrace(e));
+      }
+    }
+    return 0;
+  }
+
+  public static int parseInt(Object value) {
+    return parseInt(String.valueOf(value));
+  }
+
+  public static float parseFloat(Object value) {
+    return parseFloat(String.valueOf(value));
+  }
+
+  public static float parseFloat(String value) {
+    try {
+      if (!TextUtils.isEmpty(value) && !TextUtils.equals(value, "null")) {
+        return Float.parseFloat(value);
+      } else {
+        if (WXEnvironment.isApkDebugable()) {
+          WXLogUtils.e("WXUtils parseFloat illegal value is " + value);
+        }
+      }
+    } catch (NumberFormatException e) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.e(WXLogUtils.getStackTrace(e));
+      }
+    }
+    return 0;
+  }
+
+  public static int getInt(Object value) {
+    return getInteger(value, 0);
+  }
+
+  public static @Nullable Integer getInteger(@Nullable Object value, @Nullable Integer df) {
+
+    if (value == null) {
+      return df;
+    }
+
+    String temp = value.toString().trim();
+    String key = temp;
+    Integer cache = sCache.get(key);
+    if (cache != null) {
+      return cache;
+    } else {
+      Integer ret = df;
+      String suffix = "";
+      if (temp.length() >= 2) {
+        suffix = temp.substring(temp.length() - 2, temp.length());
+      }
+
+      if (TextUtils.equals("wx", suffix)) {
+        if (WXEnvironment.isApkDebugable()) {
+          WXLogUtils
+              .w("the value of " + value
+                  + " use wx unit, which will be not supported soon after.");
+        }
+        try {
+          ret = (int)transferWx(temp, 750);
+        } catch (NumberFormatException e) {
+          WXLogUtils.e("Argument format error! value is " + value, e);
+        } catch (Exception e) {
+          WXLogUtils.e("Argument error! value is " + value, e);
+        }
+      } else if (TextUtils.equals("px", suffix)) {
+        try {
+          temp = temp.substring(0, temp.length() - 2);
+          if (!TextUtils.isEmpty(temp) && temp.contains(".")) {
+            ret = (int)WXUtils.parseFloat(temp);
+          } else {
+            ret = Integer.parseInt(temp);
+          }
+        } catch (NumberFormatException nfe) {
+          WXLogUtils.e("Argument format error! value is " + value, nfe);
+        } catch (Exception e) {
+          WXLogUtils.e("Argument error! value is " + value, e);
+        }
+      } else {
+        try {
+          if (!TextUtils.isEmpty(temp)) {
+            if (temp.contains(".")) {
+              ret = (int)WXUtils.parseFloat(temp);
+            } else {
+              ret = Integer.parseInt(temp);
+            }
+          } else {
+            if (WXEnvironment.isApkDebugable()) {
+              WXLogUtils.e("Argument value is null, df is" + df);
+            }
+          }
+        } catch (NumberFormatException nfe) {
+          if (WXEnvironment.isApkDebugable()) {
+            WXLogUtils.w("The parameter format is not supported", nfe);
+          }
+        } catch (Exception e) {
+          WXLogUtils.e("Argument error! value is " + value, e);
+        }
+      }
+      if (ret != null && !ret.equals(df)) {
+        sCache.put(key, ret);
+      }
+      return ret;
+    }
+  }
+
+  /**
+   * Looks like no longer usage exists, Mark deprecate first.
+   * @param value
+   * @return
+   */
+  @Deprecated
+  public static long getLong(Object value) {
+    if (value == null) {
+      return 0;
+    }
+    long result = 0;
+    String temp = value.toString().trim();
+    if (temp.endsWith("wx")) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.w("the value of " + value + " use wx unit, which will be not supported soon after.");
+      }
+      try {
+        return (long)transferWx(temp, 750);
+      } catch (NumberFormatException e) {
+        WXLogUtils.e("Argument format error! value is " + value, e);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }else if (temp.endsWith("px")) {
+      try {
+        temp = temp.substring(0, temp.indexOf("px"));
+        return Long.parseLong(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }else {
+      try {
+        return Long.parseLong(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Looks like no longer usage exists, Mark deprecate first.
+   * @param value
+   * @return
+   */
+  @Deprecated
+  public static double getDouble(Object value) {
+    if (value == null) {
+      return 0;
+    }
+    double result = 0;
+    String temp = value.toString().trim();
+    if (temp.endsWith("wx")) {
+      if (WXEnvironment.isApkDebugable()) {
+        WXLogUtils.w("the value of " + value + " use wx unit, which will be not supported soon after.");
+      }
+      try {
+        return transferWx(temp, 750);
+      } catch (NumberFormatException e) {
+        WXLogUtils.e("Argument format error! value is " + value, e);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }else if (temp.endsWith("px")) {
+      try {
+        temp = temp.substring(0, temp.indexOf("px"));
+        return Double.parseDouble(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }else {
+      try {
+        return Double.parseDouble(temp);
+      } catch (NumberFormatException nfe) {
+        WXLogUtils.e("Argument format error! value is " + value, nfe);
+      } catch (Exception e) {
+        WXLogUtils.e("Argument error! value is " + value, e);
+      }
+    }
+
+    return result;
+  }
+
+  @Deprecated
+  public static boolean isTabletDevice() {
+    try{
+      return (WXEnvironment.getApplication().getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
+    }catch (Exception e){
+      //
+    }
+    return false;
+  }
+
+  public static Boolean getBoolean(@Nullable Object value, @Nullable Boolean df) {
+
+    if (value == null)
+      return df;
+    if (TextUtils.equals("false",value.toString())) {
+      return false;
+    } else if (TextUtils.equals("true",value.toString())) {
+      return true;
+    }
+    return df;
+  }
+
+  public static long getAvailMemory(Context context){
+    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+    ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
+    am.getMemoryInfo(mi);
+    //mi.availMem;
+    //return Formatter.formatFileSize(context, mi.availMem);
+    WXLogUtils.w("app AvailMemory ---->>>"+mi.availMem/(1024*1024));
+    return mi.availMem/(1024*1024);
+  }
+
+  public static String getString(@Nullable Object value,@Nullable String df) {
+
+    if (value == null)
+      return df;
+
+    String originValue;
+    if (value instanceof String) {
+      originValue = (String) value;
+    } else {
+      originValue = value.toString();
+    }
+
+    return originValue;
+  }
+
+  public static int parseUnitOrPercent(String raw, int unit) {
+    int suffix;
+    if ((suffix = raw.lastIndexOf(WXUtils.PERCENT)) != -1) {
+      return parsePercent(raw.substring(0, suffix), unit);
+    }
+    else {
+      return WXUtils.parseInt(raw);
+    }
+  }
+
+  private static int parsePercent(String raw, int unit){
+    return (int)(Float.parseFloat(raw) / HUNDRED * unit);
+  }
+
+  /**
+   * Get a banner data in JSON format from a bundle content.
+   * A bundle banner looks like below:
+   * \/*!count
+   *  * {
+   *  *   version: "0.2.1.20170104-release",
+   *  *   create: "20170207171112",
+   *  *   git: "banner--772c915",
+   *  *   digest: "c709b7f91867e371b24f54d6aeea232a"
+   *  * }
+   *  !*\/
+   *
+   * @param content a bundle content
+   * @return
+   */
+  public static String getBundleBanner(String content) {
+    final String commentBegin = "/*!";
+    final String commentEnd = "!*/";
+    final String asteriskRegex = "\\*";
+    final String replacement = "";
+
+    int offsetCountBegin = content.indexOf(commentBegin);
+    if (offsetCountBegin == -1) {
+      return null;
+    }
+    offsetCountBegin += commentBegin.length();
+    int offsetCountEnd = indexLineBreak(content, offsetCountBegin);
+    if (offsetCountEnd == -1) {
+      return null;
+    }
+    String countStr = content.substring(offsetCountBegin, offsetCountEnd);
+    int count = Integer.parseInt(countStr);
+
+    String commentBody = content.substring(offsetCountEnd + 1, offsetCountEnd + 1 + count);
+    int offsetBodyEnd = commentBody.lastIndexOf(commentEnd);
+    if (offsetBodyEnd == -1) {
+      return null;
+    }
+    commentBody = commentBody.substring(0, offsetBodyEnd);
+
+    StringBuilder commentBodyBuilder = new StringBuilder();
+    String[] items = splitLineBreak(commentBody);
+
+    for (String item : items) {
+      commentBodyBuilder.append(item.replaceFirst(asteriskRegex, replacement));
+    }
+
+    return commentBodyBuilder.toString();
+  }
+
+  private static int indexLineBreak(String str, int fromIndex) {
+    final String lineBreakIos = "\r";
+    final String lineBreakUnix = "\n";
+    final String linebreakWin = "\r\n";
+
+    int index = str.indexOf(lineBreakIos, fromIndex);
+    if (index == -1) {
+      index = str.indexOf(lineBreakUnix, fromIndex);
+    }
+    if (index == -1) {
+      index = str.indexOf(linebreakWin, fromIndex);
+    }
+
+    return index;
+  }
+
+  private static String[] splitLineBreak(String str) {
+    final String lineBreakIos = "\r";
+    final String lineBreakUnix = "\n";
+    final String linebreakWin = "\r\n";
+    String[] items = str.split(lineBreakIos);
+
+    if (items.length == 1) {
+      items = str.split(lineBreakUnix);
+    }
+    if (items.length == 1) {
+      items = str.split(linebreakWin);
+    }
+
+    return items;
+  }
+
+
+  
+  /**
+   * get number
+   * */
+  public static int getNumberInt(Object value, int defaultValue){
+    if(value == null){
+      return  defaultValue;
+    }
+    if(value instanceof  Number){
+      return  ((Number) value).intValue();
+    }
+    try{
+      String number = value.toString();
+      if(number.indexOf('.') >= 0) {
+        return (int) Float.parseFloat(value.toString());
+      }else{
+        return  Integer.parseInt(number);
+      }
+    }catch (Exception e){return  defaultValue;}
+  }
+
+  public static boolean checkGreyConfig(String group,String key,String defaultValue){
+      IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
+      if (null == configAdapter) {
+        return false;
+      }
+      double randomValue = Math.random() * 100;
+      double max = 100;
+      try {
+        String configValue = configAdapter.getConfig(group, key, defaultValue);
+        max = Double.valueOf(configValue);
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+      return randomValue < max;
+  }
+
+  private static final long sInterval = System.currentTimeMillis() - SystemClock.uptimeMillis();
+
+  public static long getFixUnixTime(){
+    return  sInterval + SystemClock.uptimeMillis();
+  }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXViewToImageUtil.java b/android/sdk/src/main/java/org/apache/weex/utils/WXViewToImageUtil.java
new file mode 100755
index 0000000..07b30dd
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXViewToImageUtil.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.MediaStore;
+import android.support.annotation.ColorInt;
+import android.view.View;
+
+import org.apache.weex.WXSDKManager;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Created by miomin on 7/25/17.
+ */
+public class WXViewToImageUtil {
+
+    public static int mBackgroundColor = Color.TRANSPARENT;
+
+    /**
+     * Generate image and return path via callback
+     */
+    public static void generateImage(final View imageView, final int width,
+                                     @ColorInt final int backgroundColor, final OnImageSavedCallback mOnImageSavedCallback) {
+
+        mBackgroundColor = backgroundColor;
+
+        // Only one save image task occurs at the same time
+        WXSDKManager.getInstance().getWXWorkThreadManager().post(new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Generate bitmap from ImageView
+                Bitmap bitmap = getBitmapFromImageView(imageView, width);
+
+                if (bitmap == null) {
+                    if (mOnImageSavedCallback != null) {
+                        mOnImageSavedCallback.onSaveFailed("Image is empty");
+                    }
+                    return;
+                }
+
+                // Sava bitmap to gallery
+                final String destPath = saveBitmapToGallery(imageView.getContext(), bitmap, mOnImageSavedCallback);
+
+                new Handler(Looper.getMainLooper()).post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (mOnImageSavedCallback != null) {
+                            mOnImageSavedCallback.onSaveSucceed(destPath);
+                            imageView.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(destPath)));
+                        }
+                    }
+                });
+            }
+        }));
+    }
+
+    /**
+     * Save bitmap to gallery
+     * @return image save path
+     */
+    public static String saveBitmapToGallery(Context context, Bitmap bitmap, final OnImageSavedCallback mOnImageSavedCallback) {
+
+        // Save image
+        File appDir = new File(Environment.getExternalStorageDirectory(), "Weex");
+        if (!appDir.exists()) {
+            appDir.mkdir();
+        }
+
+        String fileName = System.currentTimeMillis() + ".jpg";
+        File file = new File(appDir, fileName);
+
+        try {
+            FileOutputStream fos = new FileOutputStream(file);
+            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
+            fos.flush();
+            fos.close();
+        } catch (FileNotFoundException e) {
+            if (mOnImageSavedCallback != null)
+                mOnImageSavedCallback.onSaveFailed("Image creation failed due to system reason");
+            e.printStackTrace();
+        } catch (IOException e) {
+            if (mOnImageSavedCallback != null)
+                mOnImageSavedCallback.onSaveFailed("Android IOException");
+            e.printStackTrace();
+        }
+
+        // Insert the image file into the system gallery
+        try {
+            MediaStore.Images.Media.insertImage(context.getContentResolver(),
+                    file.getAbsolutePath(), fileName, null);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+
+        // Notify the system gallery update
+        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + appDir.getAbsolutePath() + "/" + fileName)));
+
+        return file.getAbsolutePath();
+    }
+
+    /**
+     * Save state callback
+     */
+    public interface OnImageSavedCallback {
+        void onSaveSucceed(String path);
+        void onSaveFailed(String errorDesc);
+    }
+
+    /**
+     * Get bitmap from imageview
+     */
+    public static Bitmap getBitmapFromImageView(final View view, int width) {
+        if (view.getWidth() <= 0 || view.getHeight() <= 0) {
+            view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
+            view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
+        }
+
+        view.setDrawingCacheEnabled(true);
+        Bitmap bitmap = view.getDrawingCache();
+        return bitmap;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXViewUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXViewUtils.java
new file mode 100644
index 0000000..a01176c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXViewUtils.java
@@ -0,0 +1,598 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+import org.apache.weex.WXSDKManager;
+import org.apache.weex.common.Constants;
+import org.apache.weex.common.WXErrorCode;
+import org.apache.weex.common.WXRuntimeException;
+import org.apache.weex.ui.component.WXComponent;
+import org.apache.weex.ui.flat.widget.Widget;
+import org.apache.weex.ui.flat.widget.WidgetGroup;
+import org.apache.weex.ui.view.border.BorderDrawable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Utility class for views
+ */
+public class WXViewUtils {
+
+  @IntDef({PixelFormat.TRANSLUCENT, PixelFormat.TRANSPARENT, PixelFormat.OPAQUE})
+  @Retention(RetentionPolicy.SOURCE)
+  public @interface Opacity {}
+
+  /**
+   * Use {@link PixelFormat#TRANSLUCENT} instead
+   */
+  @Deprecated
+  public static final int TRANSLUCENT = PixelFormat.TRANSLUCENT;
+
+  /**
+   * Use {@link PixelFormat#TRANSPARENT} instead.
+   */
+  @Deprecated
+  public static final int TRANSPARENT = PixelFormat.TRANSPARENT;
+
+  /**
+   * Use {@link PixelFormat#OPAQUE} instead
+   */
+  @Deprecated
+  public static final int OPAQUE = PixelFormat.OPAQUE;
+
+  public static final int DIMENSION_UNSET = -1;
+  private static final boolean mUseWebPx = false;
+
+  private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
+
+  @SuppressLint("NewApi")
+  public static int generateViewId() {
+
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+      for (;;) {
+        final int result = sNextGeneratedId.get();
+        // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+        int newValue = result + 1;
+        if (newValue > 0x00FFFFFF)
+          newValue = 1; // Roll over to 1, not 0.
+        if (sNextGeneratedId.compareAndSet(result, newValue)) {
+          return result;
+        }
+      }
+    } else {
+      return View.generateViewId();
+    }
+  }
+
+  private static int mScreenWidth;
+  private static int mScreenHeight;
+
+
+  public static int getWeexHeight(String instanceId){
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance != null) {
+      int weexHeight = instance.getWeexHeight();
+      if (weexHeight >= 0 || weexHeight == -2) {
+        return weexHeight;
+      }
+      else {
+        return getScreenHeight(WXEnvironment.sApplication);
+      }
+    }
+    return -3;
+  }
+
+
+
+  public static int getWeexWidth(String instanceId){
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance != null) {
+      int weexWidth = instance.getWeexWidth();
+      if (weexWidth >= 0 || weexWidth == -2) {
+        return weexWidth;
+      }
+      else {
+        return getScreenWidth(WXEnvironment.sApplication);
+      }
+    }
+    return -3;
+  }
+
+  @Deprecated
+  public static int getScreenWidth( ) {
+    return getScreenWidth(WXEnvironment.sApplication);
+  }
+
+  @Deprecated
+  public static int setScreenWidth(int screenWidth) {
+    return mScreenWidth = screenWidth;
+  }
+
+  public static float getScreenDensity(Context ctx){
+    if(ctx != null){
+      try{
+        Resources res = ctx.getResources();
+        return res.getDisplayMetrics().density;
+      }catch (Exception e){
+        WXLogUtils.e("getScreenDensityDpi exception:"+e.getMessage());
+      }
+    }
+    return Constants.Value.DENSITY;
+  }
+
+  public static void updateApplicationScreen(Context context){
+    if(context == null || WXEnvironment.sApplication == null){
+        return;
+    }
+    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+    DisplayMetrics displayMetrics = WXEnvironment.sApplication.getResources().getDisplayMetrics();
+    displayMetrics.heightPixels = metrics.heightPixels;
+    displayMetrics.widthPixels = metrics.widthPixels;
+    displayMetrics.density = metrics.density;
+    displayMetrics.densityDpi = metrics.densityDpi;
+    displayMetrics.scaledDensity = metrics.scaledDensity;
+    displayMetrics.xdpi = metrics.xdpi;
+  }
+
+  public static int getScreenWidth(Context ctx) {
+    if(ctx!=null){
+      Resources res = ctx.getResources();
+      mScreenWidth = res.getDisplayMetrics().widthPixels;
+      if(WXEnvironment.SETTING_FORCE_VERTICAL_SCREEN){
+        mScreenHeight = res
+                .getDisplayMetrics()
+                .heightPixels;
+        mScreenWidth = mScreenHeight > mScreenWidth ? mScreenWidth : mScreenHeight;
+      }
+    } else if(WXEnvironment.isApkDebugable()){
+      throw new WXRuntimeException("Error Context is null When getScreenHeight");
+    }
+    return mScreenWidth;
+  }
+
+
+  public static int getStatusBarHeight(Context context){
+      Resources resources = context.getResources();
+      int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
+      if (resourceId > 0) {
+        int statusBarHeight = resources.getDimensionPixelSize(resourceId);
+        return statusBarHeight;
+      }
+      return -1;
+  }
+
+
+  @Deprecated
+  public static int getScreenHeight() {
+    return getScreenHeight(WXEnvironment.sApplication);
+  }
+
+
+  public static int getScreenHeight(String instanceId){
+    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    return instance.isFullScreenHeightEnabled()?getFullScreenHeight(WXEnvironment.sApplication):getScreenHeight(WXEnvironment.sApplication);
+  }
+
+//get screen height with status bar on full screen
+  public static int getFullScreenHeight(Context cxt) {
+    if(cxt!=null){
+      WindowManager wm;
+      Resources res = cxt.getResources();
+      if(Build.VERSION.SDK_INT >= 17 && (wm = (WindowManager)cxt.getSystemService(Context.WINDOW_SERVICE)) != null
+              && wm.getDefaultDisplay() != null){
+        Point size = new Point();
+        wm.getDefaultDisplay().getRealSize(size);
+        mScreenHeight = size.y;
+      }
+      else {
+        mScreenHeight = cxt.getResources().getDisplayMetrics().heightPixels;
+      }
+      if(WXEnvironment.SETTING_FORCE_VERTICAL_SCREEN){
+        mScreenWidth = res
+                .getDisplayMetrics()
+                .widthPixels;
+        mScreenHeight = mScreenHeight > mScreenWidth ? mScreenHeight : mScreenWidth;
+      }
+    } else if (WXEnvironment.isApkDebugable()){
+      throw new WXRuntimeException("Error Context is null When getScreenHeight");
+    }
+    return mScreenHeight;
+  }
+//  get screen height without status bar
+  public static int getScreenHeight(Context cxt) {
+    if(cxt!=null){
+      Resources res = cxt.getResources();
+      mScreenHeight = res.getDisplayMetrics().heightPixels;
+      if(WXEnvironment.SETTING_FORCE_VERTICAL_SCREEN){
+        mScreenWidth = res
+                .getDisplayMetrics()
+                .widthPixels;
+        mScreenHeight = mScreenHeight > mScreenWidth ? mScreenHeight : mScreenWidth;
+      }
+    } else if (WXEnvironment.isApkDebugable()){
+      throw new WXRuntimeException("Error Context is null When getScreenHeight");
+    }
+    return mScreenHeight;
+  }
+
+
+  /**
+   * Convert distance from JS,CSS to native. As the JS considers the width of the screen is 750px.
+   * There must be a transform when accessing distance from JS,CSS and use it.
+   * Basically, this method calculates a scale factor(ScreenWidth/750) and use apply this scale
+   * factor to JS,CSS distance.
+   * @param pxValue the raw distance from JS or CSS. The result will be rounded to a closet int.
+   * @return the actual distance in the screen.
+   */
+
+  @Deprecated
+  public static float getRealPxByWidth(float pxValue) {
+    return getRealPxByWidth(pxValue,750);
+  }
+  public static float getRealPxByWidth(float pxValue,int customViewport) {
+    if (Float.isNaN(pxValue)) {
+      return pxValue;
+    }
+    if (mUseWebPx) {
+      return (float) Math.rint(pxValue);
+    } else {
+      float realPx = (pxValue * getScreenWidth() / customViewport);
+      return realPx > 0.005 && realPx < 1 ? 1 : (float) Math.rint(realPx);
+    }
+  }
+
+  @Deprecated
+  public static float getRealSubPxByWidth(float pxValue) {
+    return getRealSubPxByWidth(pxValue,750);
+  }
+
+  public static float getRealSubPxByWidth(float pxValue,int customViewport) {
+    if (Float.isNaN(pxValue)) {
+      return pxValue;
+    }
+    if (mUseWebPx) {
+      return (float) Math.rint(pxValue);
+    } else {
+      float realPx = (pxValue * getScreenWidth() / customViewport);
+      return realPx > 0.005 && realPx < 1 ? 1 : realPx;
+    }
+  }
+
+  /**
+   *  Internal interface that just for debug, you should never call this method because of accuracy loss obviously
+   */
+  @Deprecated
+  public static float getWeexPxByReal(float pxValue) {
+    return getWeexPxByReal(pxValue,750);
+  }
+
+  public static float getWeexPxByReal(float pxValue,int customViewport) {
+    if (Float.isNaN(pxValue)) {
+      return pxValue;
+    }
+    if (mUseWebPx) {
+      return (float) Math.rint(pxValue);
+    } else {
+      return pxValue * customViewport / getScreenWidth();
+    }
+  }
+
+  @Deprecated
+  public static float getRealPxByWidth2(float pxValue) {
+    return getRealPxByWidth2(pxValue,750);
+  }
+  public static int getRealPxByWidth2(float pxValue,int customViewport) {
+    if (mUseWebPx) {
+      return (int) pxValue;
+    } else {
+      float realPx = (pxValue * getScreenWidth() / customViewport);
+      return realPx > 0.005 && realPx < 1 ? 1 : (int) realPx - 1;
+    }
+  }
+
+  /**
+   * Convert distance from native to JS,CSS. As the JS considers the width of the screen is 750px.
+   * There must be a transform when return distance to JS,CSS.
+   * Basically, this method calculates a scale factor(ScreenWidth/750) and use apply this scale
+   * factor to native distance.
+   * @param pxValue the raw distance of native. The result will be rounded to a closet int.
+   * @return the distance in JS,CSS where the screenWidth is 750 px.
+   */
+  @Deprecated
+  public static float getWebPxByWidth(float pxValue) {
+    return getWebPxByWidth(pxValue,750);
+  }
+
+  public static float getWebPxByWidth(float pxValue,int customViewport) {
+    if (pxValue < -1.9999 && pxValue > -2.005) {
+      return Float.NaN;
+    }
+    if (mUseWebPx) {
+      return pxValue;
+    } else {
+      float realPx = (pxValue * customViewport / getScreenWidth());
+      return realPx > 0.005 && realPx < 1 ? 1 : realPx;
+    }
+  }
+
+
+  /**
+   * Convert dp to px
+   * @param dpValue the dp value to be converted
+   * @return the px value
+   */
+  public static int dip2px(float dpValue) {
+    float scale = 2;
+    try {
+      scale = WXEnvironment.getApplication().getResources()
+              .getDisplayMetrics().density;
+    } catch (Exception e) {
+      WXLogUtils.e("[WXViewUtils] dip2px:", e);
+    }
+    float finalPx = (dpValue * scale + 0.5f);
+    return finalPx > 0 && finalPx < 1 ? 1 : (int) finalPx;
+  }
+
+  public static boolean onScreenArea(View view) {
+    if (view == null || view.getVisibility() != View.VISIBLE) {
+      return false;
+    }
+
+    int[] p = new int[2];
+    view.getLocationOnScreen(p);
+    LayoutParams lp = view.getLayoutParams();
+    int viewH = 0;
+    if (lp != null) {
+      viewH = lp.height;
+    } else {
+      viewH = view.getHeight();
+    }
+
+    return (p[1] > 0 && (p[1] - WXViewUtils.getScreenHeight(WXEnvironment.sApplication) < 0))
+            || (viewH + p[1] > 0 && p[1] <= 0);
+  }
+
+  /**
+   * Multiplies the color with the given alpha.
+   *
+   * @param color color to be multiplied
+   * @param alpha value between 0 and 255
+   * @return multiplied color
+   */
+  public static int multiplyColorAlpha(int color, int alpha) {
+    if (alpha == 255) {
+      return color;
+    }
+    if (alpha == 0) {
+      return color & 0x00FFFFFF;
+    }
+    alpha = alpha + (alpha >> 7); // make it 0..256
+    int colorAlpha = color >>> 24;
+    int multipliedAlpha = colorAlpha * alpha >> 8;
+    return (multipliedAlpha << 24) | (color & 0x00FFFFFF);
+  }
+
+  @Opacity
+  public static int getOpacityFromColor(int color) {
+    int colorAlpha = color >>> 24;
+    if (colorAlpha == 255) {
+      return PixelFormat.OPAQUE;
+    } else if (colorAlpha == 0) {
+      return PixelFormat.TRANSPARENT;
+    } else {
+      return PixelFormat.TRANSLUCENT;
+    }
+  }
+
+  @SuppressWarnings("deprecation")
+  public static void setBackGround(View view, Drawable drawable, WXComponent component) {
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN){
+      view.setBackgroundDrawable(drawable);
+    }
+    else{
+      try {
+        view.setBackground(drawable);
+      } catch (Exception e) {
+        if (component == null)
+          return;
+        WXExceptionUtils.commitCriticalExceptionRT(component.getInstanceId(),
+                WXErrorCode.WX_RENDER_ERR_TEXTURE_SETBACKGROUND,
+                component.getComponentType() + " setBackGround for android view",
+                WXErrorCode.WX_RENDER_ERR_TEXTURE_SETBACKGROUND.getErrorMsg() + ": TextureView doesn't support displaying a background drawable!",
+                null);
+      }
+    }
+  }
+
+  public static @Nullable
+  BorderDrawable getBorderDrawable(@NonNull View view){
+    Drawable drawable=view.getBackground();
+    if(drawable instanceof BorderDrawable){
+      return (BorderDrawable) drawable;
+    }
+    else if(drawable instanceof LayerDrawable){
+      if(((LayerDrawable) drawable).getNumberOfLayers()>1) {
+        Drawable innerDrawable=((LayerDrawable) drawable).getDrawable(0);
+        if(innerDrawable instanceof BorderDrawable){
+          return (BorderDrawable) innerDrawable;
+        }
+      }
+    }
+    return null;
+  }
+
+  public static void clipCanvasWithinBorderBox(View targetView, Canvas canvas) {
+    Drawable drawable;
+    if (clipCanvasDueToAndroidVersion(canvas) &&
+            clipCanvasIfAnimationExist(targetView) &&
+            ((drawable = targetView.getBackground()) instanceof BorderDrawable)) {
+      BorderDrawable borderDrawable = (BorderDrawable) drawable;
+      if (borderDrawable.isRounded()) {
+        if (clipCanvasIfBackgroundImageExist(targetView, borderDrawable)) {
+          Path path = borderDrawable.getContentPath(
+                  new RectF(0, 0, targetView.getWidth(), targetView.getHeight()));
+          canvas.clipPath(path);
+        }
+      }
+    }
+  }
+
+  public static void clipCanvasWithinBorderBox(Widget widget, Canvas canvas) {
+    BorderDrawable borderDrawable;
+    if (clipCanvasDueToAndroidVersion(canvas) &&
+            clipCanvasIfAnimationExist(null) &&
+            (borderDrawable=widget.getBackgroundAndBorder())!=null ) {
+      if (borderDrawable.isRounded() && clipCanvasIfBackgroundImageExist(widget, borderDrawable)) {
+        Path path = borderDrawable.getContentPath(
+                new RectF(0, 0, widget.getBorderBox().width(), widget.getBorderBox().height()));
+        canvas.clipPath(path);
+      }
+      else {
+        canvas.clipRect(widget.getBorderBox());
+      }
+    }
+  }
+
+  /**
+   * According to https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported
+   API 18 or higher supports clipPath to canvas based on hardware acceleration.
+   * @param canvas
+   * @return
+   */
+  private static boolean clipCanvasDueToAndroidVersion(Canvas canvas) {
+    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 ||
+            !canvas.isHardwareAccelerated();
+  }
+
+  /**
+   * According to https://code.google.com/p/android/issues/detail?id=225556&sort=-id&colspec=ID
+   * clipPath doesn't work with rotation nor scale when API level is 24.
+   * As animation will not cause redraw if hardware-acceleration enabled, clipCanvas feature has
+   * to be disabled when API level is 24 without considering the animation property.
+   */
+  private static boolean clipCanvasIfAnimationExist(View targetView) {
+    if (Build.VERSION.SDK_INT != VERSION_CODES.N) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Due limitation in Android platform, the linear gradient in the following page will not be
+   * rounded if {@link Canvas#clipPath(Path)} of the parent view invoked when API level is lower
+   * than 21.
+   * http://dotwe.org/weex/963c9ade129f86757cecdd85651cd30e
+   * @param targetView
+   * @param borderDrawable
+   * @return
+   */
+  private static boolean clipCanvasIfBackgroundImageExist(@NonNull View targetView,
+                                                          @NonNull BorderDrawable borderDrawable) {
+    if (targetView instanceof ViewGroup) {
+      View child;
+      ViewGroup parent = ((ViewGroup) targetView);
+      int count = parent.getChildCount();
+      for (int i = 0; i < count; i++) {
+        child = parent.getChildAt(i);
+        if (child.getBackground() instanceof BorderDrawable &&
+                ((BorderDrawable) child.getBackground()).hasImage() &&
+                Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  private static boolean clipCanvasIfBackgroundImageExist(@NonNull Widget widget,
+                                                          @NonNull BorderDrawable borderDrawable) {
+    if (widget instanceof WidgetGroup) {
+      for (Widget child : ((WidgetGroup) widget).getChildren()) {
+        if (child.getBackgroundAndBorder().hasImage() &&
+                Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  public static boolean isViewVisible(View v) {
+    if (null == v){
+      return false;
+    }
+
+    boolean isAttachToWindow = Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT
+        ?v.isAttachedToWindow()
+        :v.getWindowToken() != null;
+
+    if (!isAttachToWindow){
+      return false;
+    }
+    if (v.getVisibility() != View.VISIBLE || v.getAlpha()<=0){
+      return false;
+    }
+
+    Drawable bacDrawable = v.getBackground();
+    if (null == bacDrawable){
+      return true;
+    }
+    if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT){
+      return bacDrawable.getAlpha()>0;
+    }
+    //< 4.4
+    if (bacDrawable instanceof ColorDrawable){
+      int alpha = Color.alpha(((ColorDrawable) bacDrawable).getColor());
+      return alpha >0;
+    }else if (bacDrawable instanceof BitmapDrawable){
+      Paint paint = ((BitmapDrawable) bacDrawable).getPaint();
+      return paint.getAlpha() > 0;
+    }
+    return true;
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXWsonJSONSwitch.java b/android/sdk/src/main/java/org/apache/weex/utils/WXWsonJSONSwitch.java
new file mode 100644
index 0000000..7676a07
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXWsonJSONSwitch.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils;
+
+import android.support.annotation.NonNull;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.weex.bridge.WXJSObject;
+import org.apache.weex.wson.Wson;
+import org.apache.weex.wson.WsonUtils;
+
+/**
+ * Created by furture on 2018/5/17.
+ */
+
+public class WXWsonJSONSwitch {
+
+    private static final String TAG = "WXSwitch";
+
+    /**
+     * switch input data to target according to config, if not use wson return normal data
+     * */
+    public static  final byte[] convertJSONToWsonIfUseWson(byte[] json){
+        if(!USE_WSON){
+            return json;
+        }
+        if(json == null){
+            return null;
+        }
+        String str = new String(json);
+        if(str.startsWith("[")){
+            return WsonUtils.toWson(JSON.parseArray(str));
+        }
+        return WsonUtils.toWson(JSON.parse(str));
+    }
+
+    /**
+     * parse json or wson data by config switch
+     * */
+    public static final Object parseWsonOrJSON(byte[] data){
+        if(data == null){
+            return  null;
+        }
+        try{
+            if(USE_WSON){
+                return  Wson.parse(data);
+            }else{
+                return  JSON.parse(new String(data, "UTF-8"));
+            }
+        }catch (Exception e){
+            WXLogUtils.e(TAG, e);
+            if(USE_WSON){  //fallback
+                return  JSON.parse(new String(data));
+            }else{
+                return Wson.parse(data);
+            }
+        }
+    }
+
+    /**
+     * to wson or wson WXJSObject
+     * */
+    public static final WXJSObject toWsonOrJsonWXJSObject(Object tasks){
+        if(tasks == null){
+            return new WXJSObject(null);
+        }
+        if(tasks.getClass() == WXJSObject.class){
+            return (WXJSObject) tasks;
+        }
+        if(USE_WSON) {
+            return new WXJSObject(WXJSObject.WSON, Wson.toWson(tasks));
+        }else{
+            return new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(tasks));
+        }
+    }
+
+
+    public static  final Object convertWXJSObjectDataToJSON(WXJSObject object){
+        if(object.type == WXJSObject.WSON){
+            return JSON.parse(Wson.parse((byte[]) object.data).toString());
+        }else{
+            return JSON.parse(object.data.toString());
+        }
+    }
+
+
+
+    /**
+     * config whether use json or wson,  you should update this value by updateGlobalConfig(String config)
+     * in WXBridgeManager class  method
+     * */
+    public static  boolean USE_WSON = true;
+
+
+    /**wson off */
+    public static final String WSON_OFF = "wson_off";
+
+
+    public @NonNull
+    static String fromObjectToJSONString(WXJSObject obj) {
+        if(obj != null && obj.type == WXJSObject.WSON){
+            Object data = Wson.parse((byte[]) obj.data);
+            if(data != null){
+                return  data.toString();
+            }
+        }
+        return WXJsonUtils.fromObjectToJSONString(obj,false);
+    }
+
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/batch/BactchExecutor.java b/android/sdk/src/main/java/org/apache/weex/utils/batch/BactchExecutor.java
new file mode 100644
index 0000000..6024dec
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/batch/BactchExecutor.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.batch;
+
+/**
+ * Created by sospartan on 8/24/16.
+ */
+public interface BactchExecutor {
+  void post(Runnable runnable);
+
+  void setInterceptor(Interceptor interceptor);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/batch/BatchOperationHelper.java b/android/sdk/src/main/java/org/apache/weex/utils/batch/BatchOperationHelper.java
new file mode 100644
index 0000000..b8d75c2
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/batch/BatchOperationHelper.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.batch;
+
+import java.util.Iterator;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Created by sospartan on 8/24/16.
+ */
+public class BatchOperationHelper implements Interceptor {
+
+
+  private BactchExecutor mExecutor;
+  private CopyOnWriteArrayList<Runnable> sRegisterTasks = new CopyOnWriteArrayList<>();
+  private boolean isCollecting = false;
+
+  public BatchOperationHelper(BactchExecutor executor){
+    mExecutor = executor;
+    executor.setInterceptor(this);
+    isCollecting = true;
+  }
+
+  @Override
+  public boolean take(Runnable runnable) {
+    if(isCollecting){
+      sRegisterTasks.add(runnable);
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Post all tasks to executor. Can only be called once.
+   */
+  public void flush(){
+    isCollecting = false;
+    mExecutor.post(new Runnable() {
+      @Override
+      public void run() {
+        Iterator<Runnable> iterator = sRegisterTasks.iterator();
+        while(iterator.hasNext()){
+          Runnable item = iterator.next();
+          item.run();
+//          iterator.remove();
+          sRegisterTasks.remove(item);
+        }
+      }
+    });
+    mExecutor.setInterceptor(null);
+  }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/batch/Interceptor.java b/android/sdk/src/main/java/org/apache/weex/utils/batch/Interceptor.java
new file mode 100644
index 0000000..a63142c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/batch/Interceptor.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.batch;
+
+/**
+ * Created by sospartan on 8/24/16.
+ */
+public interface Interceptor {
+  boolean take(Runnable runnable);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/cache/RegisterCache.java b/android/sdk/src/main/java/org/apache/weex/utils/cache/RegisterCache.java
new file mode 100644
index 0000000..d55e3ee
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/cache/RegisterCache.java
@@ -0,0 +1,181 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.cache;
+
+import org.apache.weex.bridge.ModuleFactory;
+import org.apache.weex.bridge.WXModuleManager;
+import org.apache.weex.ui.IFComponentHolder;
+import org.apache.weex.ui.WXComponentRegistry;
+import org.apache.weex.ui.config.AutoScanConfigRegister;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class RegisterCache {
+    private static Map<String, ModuleCache> moduleCacheMap = new ConcurrentHashMap<>();
+    private static Map<String, ComponentCache> componentCacheMap = new ConcurrentHashMap<>();
+    private static RegisterCache registerCache;
+
+    private boolean enable = false;
+
+    private boolean enableAutoScan = true;
+
+    public static RegisterCache getInstance() {
+        if (registerCache == null) {
+            synchronized (RegisterCache.class) {
+                if (registerCache == null) {
+                    registerCache = new RegisterCache();
+                }
+            }
+        }
+        return registerCache;
+    }
+
+    private RegisterCache() {
+
+    }
+
+    private volatile boolean finished = false;
+
+    private volatile int doNotCacheSize = Integer.MAX_VALUE;
+
+    public void setEnable(boolean enable) {
+        this.enable = enable;
+    }
+
+    private boolean enableCache() {
+        return enable;
+    }
+
+    private boolean canCache() {
+        return enableCache()
+                && !finished
+                && getDoNotCacheSize() < 1;
+    }
+
+    public boolean enableAutoScan() {
+        return enableAutoScan;
+    }
+
+    public void setEnableAutoScan(boolean enableAutoScan) {
+        if(this.enableAutoScan != enableAutoScan) {
+            if(enableAutoScan) {
+                AutoScanConfigRegister.doScanConfig();
+            }
+            this.enableAutoScan = enableAutoScan;
+        }
+
+    }
+
+    private int getDoNotCacheSize() {
+        return doNotCacheSize--;
+    }
+
+    public void setDoNotCacheSize(int doNotCacheSize) {
+        this.doNotCacheSize = doNotCacheSize;
+    }
+
+    public boolean idle(boolean atCreateInstance) {
+        if (finished)
+            return true;
+
+        String message;
+        if(atCreateInstance) {
+            message = "idle from create instance";
+        } else {
+            message = "idle from external";
+        }
+
+        WXLogUtils.e(message + " cache size is " + (moduleCacheMap.size() + componentCacheMap.size()));
+
+        finished = true;
+        CacheComponentRegister();
+        CacheModuleRegister();
+        return true;
+    }
+
+    public boolean cacheModule(final String moduleName, final ModuleFactory factory, final boolean global) {
+        if (!canCache()) {
+            return false;
+        }
+        try {
+            moduleCacheMap.put(moduleName, new ModuleCache(moduleName, factory, global));
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+
+    public boolean cacheComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) {
+        if (!canCache()) {
+            return false;
+        }
+        try {
+            componentCacheMap.put(type, new ComponentCache(type, holder, componentInfo));
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+
+    private void CacheComponentRegister() {
+        if (componentCacheMap.isEmpty())
+            return;
+        WXComponentRegistry.registerComponent(componentCacheMap);
+    }
+
+
+    private void CacheModuleRegister() {
+        if (moduleCacheMap.isEmpty())
+            return;
+
+        WXModuleManager.registerModule(moduleCacheMap);
+    }
+
+    public class ModuleCache {
+        public final String name;
+        public final ModuleFactory factory;
+        public final boolean global;
+
+        ModuleCache(String moduleName, ModuleFactory factory, boolean global) {
+            this.name = moduleName;
+            this.factory = factory;
+            this.global = global;
+        }
+    }
+
+
+    public class ComponentCache {
+        public final String type;
+        public final IFComponentHolder holder;
+        public final Map<String, Object> componentInfo;
+
+        ComponentCache(String type, IFComponentHolder holder, Map<String, Object> componentInfo) {
+            this.type = type;
+            this.componentInfo = componentInfo;
+            this.holder = holder;
+        }
+    }
+
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/tools/Info.java b/android/sdk/src/main/java/org/apache/weex/utils/tools/Info.java
new file mode 100644
index 0000000..dd98213
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/tools/Info.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.tools;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class Info{
+
+	public Info() {
+		taskInfo = new TaskInfo();
+	}
+
+	@JSONField(name="instanceId")
+	public String instanceId;
+
+	@JSONField(name="taskName")
+	public String taskName;
+
+	@JSONField(name="taskInfo")
+	public TaskInfo taskInfo;
+
+	@JSONField(name="platform")
+	public String platform;
+
+	@JSONField(name="taskId")
+	public int taskId;
+
+	@Override
+ 	public String toString(){
+		return 
+			"Info : {" +
+			"instanceId = '" + instanceId + '\'' + 
+			",taskName = '" + taskName + '\'' + 
+			",taskInfo = '" + taskInfo + '\'' + 
+			",platform = '" + platform + '\'' + 
+			",taskId = '" + taskId + '\'' + 
+			"}";
+		}
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/tools/LogDetail.java b/android/sdk/src/main/java/org/apache/weex/utils/tools/LogDetail.java
new file mode 100644
index 0000000..81ff122
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/tools/LogDetail.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.tools;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import org.apache.weex.WXEnvironment;
+import java.util.Locale;
+
+public class LogDetail {
+    public static final String KeyWrod_Init = "Weex_Init";
+    public static final String KeyWords_Render = "Weex_Render";
+
+    public LogDetail() {
+        time = new Time();
+        info = new Info();
+    }
+
+    @JSONField(name = "time")
+    public Time time;
+
+    @JSONField(name = "Info")
+    public Info info;
+
+    @Override
+    public String toString() {
+        return
+                "taskName : " + info.taskName + " - LogDetail : {" +
+                        "time = '" + time + '\'' +
+                        ", info = '" + info + '\'' +
+                        "}";
+    }
+
+
+    public String keyWords = KeyWords_Render;
+
+    public void println() {
+        if(WXEnvironment.isPerf())
+        Log.e(TimeCalculator.TIMELINE_TAG," timeline " + this.keyWords + " java LogDetail: " + this.toString());
+    }
+
+    public void name(String name) {
+        time.constructor();
+        info.taskName = name;
+        if(!TextUtils.isEmpty(name)) {
+            String s = name.toLowerCase(Locale.ROOT);
+            if(s.contains("module")
+            || s.contains("component")
+                    || s.contains("framework")) {
+                this.keyWords = KeyWrod_Init;
+            }
+        }
+    }
+
+    public void keyWorkds(String keyWords) {
+        this.keyWords = keyWords;
+    }
+
+    public void taskStart() {
+        time.taskStart();
+    }
+
+    public void taskEnd() {
+        time.taskEnd();
+        println();
+    }
+
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/tools/LogSwitch.java b/android/sdk/src/main/java/org/apache/weex/utils/tools/LogSwitch.java
new file mode 100644
index 0000000..bc5c12a
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/tools/LogSwitch.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.tools;
+
+public class LogSwitch {
+
+    private int low_level = 4;
+    private int medium_level = 2;
+    private int high_level = 1;
+    private int log_switch = 0;
+    private boolean showLowLevelLog = false;
+    private boolean showMediumLevelLog = false;
+    private boolean showHighLevelLog = true;
+
+
+    public void setLog_switch() {
+        // Todo
+        // read prop
+
+        if (showLowLevelLog)
+            log_switch |= low_level;
+
+        if (showMediumLevelLog) {
+            log_switch |= medium_level;
+        }
+
+        if (showHighLevelLog) {
+            log_switch |= high_level;
+        }
+    }
+
+
+    public int getLog_switch() {
+        return log_switch;
+    }
+
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/tools/TaskInfo.java b/android/sdk/src/main/java/org/apache/weex/utils/tools/TaskInfo.java
new file mode 100644
index 0000000..34abfcf
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/tools/TaskInfo.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.tools;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class TaskInfo{
+
+	@JSONField(name="args")
+	public String args;
+
+	@JSONField(name="relateTaskId")
+	public int relateTaskId;
+
+	@Override
+ 	public String toString(){
+		return 
+			"TaskInfo{" + 
+			"args = '" + args + '\'' + 
+			",relateTaskId = '" + relateTaskId + '\'' + 
+			"}";
+		}
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/tools/Time.java b/android/sdk/src/main/java/org/apache/weex/utils/tools/Time.java
new file mode 100644
index 0000000..eb5a6c7
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/tools/Time.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.tools;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class Time {
+
+    @JSONField(name = "taskStart")
+    public long taskStart;
+
+    @JSONField(name = "execTime")
+    public long execTime;
+
+    @JSONField(name = "constructor")
+    public long constructor;
+
+    @JSONField(name = "destructor")
+    public long destructor;
+
+    @JSONField(name = "taskEnd")
+    public long taskEnd;
+
+    @JSONField(name = "waitTime")
+    public long waitTime;
+
+    @Override
+    public String toString() {
+        return
+                "time : {" +
+                        "constructor = '" + constructor + '\'' +
+                        ",taskStart = '" + taskStart + '\'' +
+                        ",execTime = '" + execTime + '\'' +
+                        ",waitTime = '" + waitTime + '\'' +
+                        ",destructor = '" + destructor + '\'' +
+                        ",taskEnd = '" + taskEnd + '\'' +
+                        "}";
+    }
+
+
+    protected void constructor() {
+        constructor = System.currentTimeMillis();
+    }
+
+    public void execTime() {
+        execTime = taskEnd - taskStart;
+    }
+
+    public void taskStart() {
+        taskStart = System.currentTimeMillis();
+    }
+
+    public void taskEnd() {
+        taskEnd = System.currentTimeMillis();
+        execTime();
+        destructor();
+    }
+
+    private void destructor() {
+        waitTime();
+        destructor = System.currentTimeMillis();
+    }
+
+    public void waitTime() {
+        waitTime = taskStart - constructor;
+    }
+}
\ No newline at end of file
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/tools/TimeCalculator.java b/android/sdk/src/main/java/org/apache/weex/utils/tools/TimeCalculator.java
new file mode 100644
index 0000000..deb4809
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/utils/tools/TimeCalculator.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.utils.tools;
+
+import android.util.Log;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.weex.WXEnvironment;
+import org.apache.weex.WXSDKInstance;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class TimeCalculator {
+
+    public static final String TIMELINE_TAG = "timeline";
+
+    public static final String PLATFORM_ANDROID = "Android";
+
+    private CopyOnWriteArrayList<LogDetail> logRecorder;
+    public TimeCalculator(WXSDKInstance instance) {
+        logRecorder = new CopyOnWriteArrayList<LogDetail>();
+    }
+
+    public void addLog(LogDetail logDetail) {
+        if(!WXEnvironment.isPerf()) {
+            return;
+        }
+        logRecorder.add(logDetail);
+    }
+
+    public LogDetail createLogDetail(String name) {
+        LogDetail logDetail = new LogDetail();
+        logDetail.name(name);
+        addLog(logDetail);
+        return logDetail;
+    }
+
+    public void println() {
+        if(!WXEnvironment.isPerf()) {
+            return;
+        }
+
+        for (LogDetail l: logRecorder) {
+            Log.e(TIMELINE_TAG, JSON.toJSONString(l));
+        }
+
+    }
+
+
+    private String test = "{\"time\":{\"execTime\":0,\"constructor\":0,\"destructor\":0,\"taskStart\":0,\"taskEnd\":0,\"waitTime\":0},\"Info\":{\"taskInfo\":{\"relateTaskId\":0,\"args\":\"stringReplace\"},\"taskName\":\"stringReplace\",\"instanceId\":\"1\",\"platform\":\"stringReplace\",\"taskId\":0}}";
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/wson/Wson.java b/android/sdk/src/main/java/org/apache/weex/wson/Wson.java
new file mode 100644
index 0000000..4d1098b
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/wson/Wson.java
@@ -0,0 +1,820 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.wson;
+
+
+import android.support.v4.util.LruCache;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONField;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * fast binary json format for parse map and serialize map
+ * Created by efurture on 2017/8/16.
+ */
+public class Wson {
+
+    /**
+     * skip map null values
+     * */
+    public static final boolean WriteMapNullValue = false;
+    /**
+     * wson data type
+     * */
+    private static final byte NULL_TYPE = '0';
+
+    private static final byte STRING_TYPE = 's';
+
+    private static final byte BOOLEAN_TYPE_TRUE = 't';
+
+    private static final byte BOOLEAN_TYPE_FALSE = 'f';
+
+    private static final byte NUMBER_INT_TYPE = 'i';
+
+    private static final byte NUMBER_LONG_TYPE = 'l';
+
+    private static final byte NUMBER_BIG_INTEGER_TYPE = 'g';
+
+    private static final byte NUMBER_BIG_DECIMAL_TYPE = 'e';
+
+    private static final byte NUMBER_DOUBLE_TYPE = 'd';
+
+    private static final byte NUMBER_FLOAT_TYPE = 'F';
+
+    private static final byte ARRAY_TYPE = '[';
+
+    private static final byte MAP_TYPE = '{';
+
+    /**
+     * StringUTF-16, byte order with native byte order
+     * */
+    private static final boolean IS_NATIVE_LITTLE_ENDIAN = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
+
+
+    /**
+     * parse wson data  to object, please use WXJsonUtils.parseWson
+     * @param  data  byte array
+     * */
+    public static final Object parse(byte[] data){
+        if(data == null){
+            return  null;
+        }
+        try{
+            Parser parser =  new Parser(data);
+            Object object = parser.parse();
+            parser.close();
+            return object;
+        }catch (Exception e){
+            WXLogUtils.e("parseWson", e);
+            return  null;
+        }
+    }
+
+
+    /**
+     * serialize object to wson data, please use WXJsonUtils.toWsonOrJsonWXJSObject
+     * */
+    public static final byte[] toWson(Object object){
+        if(object == null){
+            return  null;
+        }
+        Builder builder = new Builder();
+        byte[]  bts  = builder.toWson(object);
+        builder.close();
+        return bts;
+    }
+
+
+    /**
+     * wson data parser
+     * */
+    private static final class Parser {
+
+        private int position = 0;
+        private byte[] buffer;
+        private char[]  charsBuffer;
+
+        private Parser(byte[] buffer) {
+            this.buffer = buffer;
+            charsBuffer = localCharsBufferCache.get();
+            if(charsBuffer != null){
+                localCharsBufferCache.set(null);
+            }else{
+                charsBuffer = new char[512];
+            }
+        }
+
+
+        private   final Object parse(){
+            return  readObject();
+        }
+
+        private final void close(){
+            position = 0;
+            buffer = null;
+            if(charsBuffer != null){
+                localCharsBufferCache.set(charsBuffer);
+            }
+            charsBuffer = null;
+        }
+
+        private final Object readObject(){
+            byte type  = readType();
+            switch (type){
+                case STRING_TYPE:
+                    return readUTF16String();
+                case NUMBER_INT_TYPE :
+                    return  readVarInt();
+                case NUMBER_FLOAT_TYPE :
+                    return  readFloat();
+                case MAP_TYPE:
+                    return readMap();
+                case ARRAY_TYPE:
+                    return readArray();
+                case NUMBER_DOUBLE_TYPE :
+                    return readDouble();
+                case NUMBER_LONG_TYPE :
+                    return  readLong();
+                case NUMBER_BIG_INTEGER_TYPE :
+                    return  new BigInteger(readUTF16String());
+                case NUMBER_BIG_DECIMAL_TYPE :
+                    return  new BigDecimal(readUTF16String());
+                case BOOLEAN_TYPE_FALSE:
+                    return  Boolean.FALSE;
+                case BOOLEAN_TYPE_TRUE:
+                    return  Boolean.TRUE;
+                case NULL_TYPE:
+                    return  null;
+                default:
+                    throw new RuntimeException("wson unhandled type " + type + " " +
+                            position  +  " length " + buffer.length);
+            }
+        }
+
+
+
+        private final Object readMap(){
+            int size = readUInt();
+            Map<String, Object> object = new JSONObject();;
+            for(int i=0; i<size; i++){
+                String key = readMapKeyUTF16();
+                Object value = readObject();
+                object.put(key, value);
+            }
+            return object;
+        }
+
+        private final Object readArray(){
+            int length = readUInt();
+            List<Object> array = new JSONArray(length);
+            for(int i=0; i<length; i++){
+                array.add(readObject());
+            }
+            return  array;
+        }
+
+        private  final byte readType(){
+            byte type = buffer[position];
+            position ++;
+            return  type;
+        }
+
+
+        private final String readMapKeyUTF16() {
+            int length = readUInt();
+            length = length/2;
+            if(charsBuffer.length < length){
+                charsBuffer = new char[length];
+            }
+            int hash = 5381;
+            if(IS_NATIVE_LITTLE_ENDIAN){
+                for(int i=0; i<length; i++){
+                    char ch = (char) ((buffer[position] & 0xFF) +
+                            (buffer[position + 1] << 8));
+                    charsBuffer[i] = (ch);
+                    hash = ((hash << 5) + hash)  + ch;
+                    position+=2;
+                }
+            }else{
+                for(int i=0; i<length; i++){
+                    char ch = (char) ((buffer[position + 1] & 0xFF) +
+                            (buffer[position] << 8));
+                    charsBuffer[i] = (ch);
+                    hash = ((hash << 5) + hash)  + ch;
+                    position+=2;
+                }
+            }
+            int globalIndex = (globalStringBytesCache.length - 1)&hash;
+            String cache = globalStringBytesCache[globalIndex];
+            if(cache != null
+                    && cache.length() == length){
+                boolean isStringEqual  = true;
+                for(int i=0; i<length; i++){
+                    if(charsBuffer[i] != cache.charAt(i)){
+                        isStringEqual = false;
+                        break;
+                    }
+                }
+                if(isStringEqual) {
+                    return cache;
+                }
+            }
+            cache = new String(charsBuffer, 0, length);
+            if(length < 64) {
+                globalStringBytesCache[globalIndex] = cache;
+            }
+            return  cache;
+        }
+
+        private final String readUTF16String(){
+            int length = readUInt()/2;
+            if(charsBuffer.length < length){
+                charsBuffer = new char[length];
+            }
+            if(IS_NATIVE_LITTLE_ENDIAN){
+                for(int i=0; i<length; i++){
+                    char ch = (char) ((buffer[position] & 0xFF) +
+                            (buffer[position + 1] << 8));
+                    charsBuffer[i] = (ch);
+                    position+=2;
+                }
+            }else{
+                for(int i=0; i<length; i++){
+                    char ch = (char) ((buffer[position + 1] & 0xFF) +
+                            (buffer[position] << 8));
+                    charsBuffer[i] = (ch);
+                    position+=2;
+                }
+            }
+            return  new String(charsBuffer, 0, length);
+        }
+
+
+
+
+
+        private   final int readVarInt(){
+            int raw = readUInt();
+            // This undoes the trick in putVarInt()
+            int num = (((raw << 31) >> 31) ^ raw) >> 1;
+            // This extra step lets us deal with the largest signed values by treating
+            // negative results from read unsigned methods as like unsigned values.
+            // Must re-flip the top bit if the original read value had it set.
+            return num ^ (raw & (1 << 31));
+        }
+
+        private final  int readUInt(){
+            int value = 0;
+            int i = 0;
+            int b;
+            while (((b = buffer[position]) & 0x80) != 0) {
+                value |= (b & 0x7F) << i;
+                i += 7;
+                position+=1;
+                if (i > 35) {
+                    throw new IllegalArgumentException("Variable length quantity is too long");
+                }
+            }
+            position+=1;
+            return value | (b << i);
+        }
+
+        private final long readLong(){
+            long number = (((buffer[position + 7] & 0xFFL)      ) +
+                    ((buffer[position + 6] & 0xFFL) <<  8) +
+                    ((buffer[position + 5] & 0xFFL) << 16) +
+                    ((buffer[position + 4] & 0xFFL) << 24) +
+                    ((buffer[position + 3] & 0xFFL) << 32) +
+                    ((buffer[position + 2] & 0xFFL) << 40) +
+                    ((buffer[position + 1] & 0xFFL) << 48) +
+                    (((long) buffer[position])      << 56));
+            position += 8;
+            return  number;
+        }
+
+        private  final Object readDouble(){
+            double number = Double.longBitsToDouble(readLong());
+            if(number > Integer.MAX_VALUE){
+                long numberLong = (long) number;
+                double doubleLong = (numberLong);
+                if(number - doubleLong < Double.MIN_NORMAL){
+                    return numberLong;
+                }
+            }
+            return  number;
+        }
+
+        private Object readFloat() {
+            int number = (((buffer[position + 3] & 0xFF)      ) +
+                    ((buffer[position + 2] & 0xFF) <<  8) +
+                    ((buffer[position + 1] & 0xFF) << 16) +
+                    ((buffer[position  ] & 0xFF) << 24));
+            position +=4;
+            return  Float.intBitsToFloat(number);
+        }
+    }
+
+    /**
+     * wson builder
+     * */
+    private static final class Builder {
+
+        private byte[] buffer;
+        private int position;
+        private ArrayList refs;
+        private final static ThreadLocal<byte[]> bufLocal = new ThreadLocal<byte[]>();
+        private final static ThreadLocal<ArrayList> refsLocal = new ThreadLocal<ArrayList>();
+
+
+
+        private Builder(){
+            buffer =  bufLocal.get();
+            if(buffer != null) {
+                bufLocal.set(null);
+            }else{
+                buffer = new byte[1024];
+            }
+            refs = refsLocal.get();
+            if(refs != null){
+                refsLocal.set(null);
+            }else{
+                refs = new ArrayList<>(16);
+            }
+        }
+
+
+        private final byte[] toWson(Object object){
+            writeObject(object);
+            byte[] bts = new byte[position];
+            System.arraycopy(buffer, 0, bts, 0, position);
+            return  bts;
+        }
+
+        private final void close(){
+            if(buffer.length <= 1024*16){
+                bufLocal.set(buffer);
+            }
+            if(refs.isEmpty()){
+                refsLocal.set(refs);
+            }else{
+                refs.clear();
+            }
+            refs = null;
+            buffer = null;
+            position = 0;
+        }
+
+        private final void writeObject(Object object) {
+            if(object instanceof  CharSequence){
+                ensureCapacity(2);
+                writeByte(STRING_TYPE);
+                writeUTF16String((CharSequence) object);
+                return;
+            }else if (object instanceof Map){
+                if(refs.contains(object)){
+                    ensureCapacity(2);
+                    writeByte(NULL_TYPE);
+                    return;
+                }
+                refs.add(object);
+                Map map = (Map) object;
+                writeMap(map);
+                refs.remove(refs.size()-1);
+                return;
+            }else if (object instanceof List){
+                if(refs.contains(object)){
+                    ensureCapacity(2);
+                    writeByte(NULL_TYPE);
+                    return;
+                }
+                refs.add(object);
+                ensureCapacity(8);
+                List list = (List) object;
+                writeByte(ARRAY_TYPE);
+                writeUInt(list.size());
+                for(Object value : list){
+                    writeObject(value);
+                }
+                refs.remove(refs.size()-1);
+                return;
+            }else if (object instanceof Number){
+                Number number = (Number) object;
+                writeNumber(number);
+                return;
+            }else if (object instanceof  Boolean){
+                ensureCapacity(2);
+                Boolean value  = (Boolean) object;
+                if(value){
+                    writeByte(BOOLEAN_TYPE_TRUE);
+                }else{
+                    writeByte(BOOLEAN_TYPE_FALSE);
+                }
+                return;
+            }else if(object == null){
+                ensureCapacity(2);
+                writeByte(NULL_TYPE);
+                return;
+            }else if (object.getClass().isArray()){
+                if(refs.contains(object)){
+                    ensureCapacity(2);
+                    writeByte(NULL_TYPE);
+                    return;
+                }
+                refs.add(object);
+                ensureCapacity(8);
+                int length = Array.getLength(object);
+                writeByte(ARRAY_TYPE);
+                writeUInt(length);
+                for(int i=0; i<length; i++){
+                    Object value = Array.get(object, i);
+                    writeObject(value);
+                }
+                refs.remove(refs.size()-1);
+                return;
+            }else  if(object instanceof  Date){
+                ensureCapacity(10);
+                double date = ((Date)object).getTime();
+                writeByte(NUMBER_DOUBLE_TYPE);
+                writeDouble(date);
+            }else  if(object instanceof  Calendar){
+                ensureCapacity(10);
+                double date = ((Calendar)object).getTime().getTime();
+                writeByte(NUMBER_DOUBLE_TYPE);
+                writeDouble(date);
+            }else  if(object instanceof  Collection){
+                if(refs.contains(object)){
+                    ensureCapacity(2);
+                    writeByte(NULL_TYPE);
+                    return;
+                }
+                refs.add(object);
+                ensureCapacity(8);
+                Collection list = (Collection) object;
+                writeByte(ARRAY_TYPE);
+                writeUInt(list.size());
+                for(Object value : list){
+                    writeObject(value);
+                }
+                refs.remove(refs.size()-1);
+            }else{
+                if(refs.contains(object)){
+                    ensureCapacity(2);
+                    writeByte(NULL_TYPE);
+                }else {
+                    refs.add(object);
+                    if(object.getClass().isEnum()){
+                        writeObject(JSON.toJSONString(object));
+                    }else{
+                        writeAdapterObject(object);
+                    }
+                    refs.remove(refs.size()-1);
+                }
+                return;
+            }
+        }
+
+        private final void writeNumber(Number number) {
+            ensureCapacity(12);
+            if(number instanceof  Integer){
+                writeByte(NUMBER_INT_TYPE);
+                writeVarInt(number.intValue());
+                return;
+            }
+
+            if(number instanceof Float){
+                writeByte(NUMBER_FLOAT_TYPE);
+                writeFloat(number.floatValue());
+                return;
+            }
+            if(number instanceof  Double){
+                writeByte(NUMBER_DOUBLE_TYPE);
+                writeDouble(number.doubleValue());
+                return;
+            }
+
+            if(number instanceof  Long){
+                writeByte(NUMBER_LONG_TYPE);
+                writeLong(number.longValue());
+                return;
+            }
+
+            if(number instanceof  Short
+                    || number instanceof  Byte){
+                writeByte(NUMBER_INT_TYPE);
+                writeVarInt(number.intValue());
+                return;
+            }
+
+            if(number instanceof BigInteger){
+                writeByte(NUMBER_BIG_INTEGER_TYPE);
+                writeUTF16String(number.toString());
+                return;
+            }
+
+            if(number instanceof BigDecimal){
+                String value = number.toString();
+                double doubleValue = number.doubleValue();
+                if(value.equals(Double.toString(doubleValue))){
+                    writeByte(NUMBER_DOUBLE_TYPE);
+                    writeDouble(doubleValue);
+                }else {
+                    writeByte(NUMBER_BIG_DECIMAL_TYPE);
+                    writeUTF16String(value);
+                }
+                return;
+            }
+            writeByte(STRING_TYPE);
+            writeUTF16String(number.toString());
+
+        }
+
+        private final  void writeMap(Map map) {
+            if(WriteMapNullValue){
+                ensureCapacity(8);
+                writeByte(MAP_TYPE);
+                writeUInt(map.size());
+                Set<Map.Entry<Object,Object>>  entries = map.entrySet();
+                for(Map.Entry<Object,Object> entry : entries){
+                    writeMapKeyUTF16(entry.getKey().toString());
+                    writeObject(entry.getValue());
+                }
+            }else{
+                Set<Map.Entry<Object,Object>>  entries = map.entrySet();
+                int nullValueSize = 0;
+                for(Map.Entry<Object,Object> entry : entries){
+                    if(entry.getValue() == null){
+                        nullValueSize++;
+                    }
+                }
+
+                ensureCapacity(8);
+                writeByte(MAP_TYPE);
+                writeUInt(map.size()-nullValueSize);
+                for(Map.Entry<Object,Object> entry : entries){
+                    if(entry.getValue() == null){
+                        continue;
+                    }
+                    writeMapKeyUTF16(entry.getKey().toString());
+                    writeObject(entry.getValue());
+                }
+            }
+        }
+
+
+        private final void writeByte(byte type){
+            buffer[position] = type;
+            position++;
+        }
+
+        private final void writeAdapterObject(Object object){
+            if(specialClass.get(object.getClass().getName()) != null){
+                writeObject(JSON.toJSON(object));
+                return;
+            }
+            try{
+                writeMap(toMap(object));
+            }catch (Exception e){
+                specialClass.put(object.getClass().getName(), true);
+                writeObject(JSON.toJSON(object));
+            }
+        }
+
+        private  final Map  toMap(Object object){
+            Map map = new JSONObject();
+            try {
+                Class<?> targetClass = object.getClass();
+                String key = targetClass.getName();
+                List<Method> methods = getBeanMethod(key, targetClass);
+                for (Method method : methods) {
+                    String methodName = method.getName();
+                    if (methodName.startsWith(METHOD_PREFIX_GET)) {
+                        Object value = method.invoke(object);
+                        if(value != null){
+                            StringBuilder builder = new StringBuilder(method.getName().substring(3));
+                            builder.setCharAt(0, Character.toLowerCase(builder.charAt(0)));
+                            map.put(builder.toString(), (Object) value);
+                        }
+                    }else if(methodName.startsWith(METHOD_PREFIX_IS)){
+                        Object value = method.invoke(object);
+                        if(value != null){
+                            StringBuilder builder = new StringBuilder(method.getName().substring(2));
+                            builder.setCharAt(0, Character.toLowerCase(builder.charAt(0)));
+                            map.put(builder.toString(), value);
+                        }
+                    }
+                }
+                List<Field> fields = getBeanFields(key, targetClass);
+                for(Field field : fields){
+                    String fieldName = field.getName();
+                    if(map.containsKey(fieldName)){
+                        continue;
+                    }
+                    Object value  = field.get(object);
+                    if(value == null){
+                        continue;
+                    }
+                    map.put(fieldName, value);
+                }
+            }catch (Exception e){
+                if(e instanceof  RuntimeException){
+                    throw  (RuntimeException)e;
+                }else{
+                    throw  new RuntimeException(e);
+                }
+            }
+            return  map;
+        }
+
+        private  final void writeMapKeyUTF16(String value){
+            writeUTF16String(value);
+        }
+
+
+
+
+        /**
+         * writeString UTF-16
+         * */
+        private  final void writeUTF16String(CharSequence value){
+            int length = value.length();
+            ensureCapacity(length*2 + 8);
+            writeUInt(length*2);
+            if(IS_NATIVE_LITTLE_ENDIAN){
+                for(int i=0; i<length; i++){
+                    char ch = value.charAt(i);
+                    buffer[position] = (byte) (ch);
+                    buffer[position+1] = (byte) (ch >>> 8);
+                    position+=2;
+                }
+            }else{
+                for(int i=0; i<length; i++){
+                    char ch = value.charAt(i);
+                    buffer[position + 1] = (byte) (ch      );
+                    buffer[position] = (byte) (ch >>> 8);
+                    position+=2;
+                }
+            }
+        }
+
+
+        private final void writeDouble(double value){
+            writeLong(Double.doubleToLongBits(value));
+        }
+
+        private final void writeFloat(float value){
+            int val = Float.floatToIntBits(value);
+            buffer[position + 3] = (byte) (val       );
+            buffer[position + 2] = (byte) (val >>>  8);
+            buffer[position + 1] = (byte) (val >>> 16);
+            buffer[position ] = (byte) (val >>> 24);
+            position += 4;
+        }
+
+        private final void writeLong(long val){
+            buffer[position + 7] = (byte) (val       );
+            buffer[position + 6] = (byte) (val >>>  8);
+            buffer[position + 5] = (byte) (val >>> 16);
+            buffer[position + 4] = (byte) (val >>> 24);
+            buffer[position + 3] = (byte) (val >>> 32);
+            buffer[position + 2] = (byte) (val >>> 40);
+            buffer[position + 1] = (byte) (val >>> 48);
+            buffer[position    ] = (byte) (val >>> 56);
+            position += 8;
+        }
+
+        private final void writeVarInt(int value){
+            writeUInt((value << 1) ^ (value >> 31));
+        }
+
+        private final void  writeUInt(int value){
+            while ((value & 0xFFFFFF80) != 0) {
+                buffer[position] = (byte)((value & 0x7F) | 0x80);
+                position++;
+                value >>>= 7;
+            }
+            buffer[position] = (byte)(value & 0x7F);
+            position++;
+        }
+
+
+        private final void ensureCapacity(int minCapacity) {
+            minCapacity += position;
+            // overflow-conscious code
+            if (minCapacity - buffer.length > 0){
+                int oldCapacity = buffer.length;
+                int newCapacity = oldCapacity << 1;
+                if(newCapacity < 1024*16){
+                    newCapacity = 1024*16;
+                }
+                if (newCapacity - minCapacity < 0) {
+                    newCapacity = minCapacity;
+                }
+                buffer = Arrays.copyOf(buffer, newCapacity);
+            }
+        }
+    }
+
+
+    /**
+     * cache json property key, most of them all same
+     * */
+    private static final int GLOBAL_STRING_CACHE_SIZE = 2*1024;
+    private static final ThreadLocal<char[]> localCharsBufferCache = new ThreadLocal<>();
+    private static final String[] globalStringBytesCache = new String[GLOBAL_STRING_CACHE_SIZE];
+
+
+
+
+    /**
+     * lru cache, to map helper
+     * */
+    private static final String METHOD_PREFIX_GET = "get";
+    private static final String METHOD_PREFIX_IS = "is";
+    private static LruCache<String, List<Method>> methodsCache = new LruCache<>(128);
+    private static LruCache<String, List<Field>> fieldsCache = new LruCache<>(128);
+    private static LruCache<String, Boolean> specialClass = new LruCache<>(16);
+
+
+    private static final List<Method> getBeanMethod(String key, Class targetClass){
+        List<Method> methods = methodsCache.get(key);
+        if(methods == null){
+            methods = new ArrayList<>();
+            Method[]  allMethods = targetClass.getMethods();
+            for(Method method : allMethods){
+                if(method.getDeclaringClass() == Object.class){
+                    continue;
+                }
+                if( (method.getModifiers() & Modifier.STATIC) != 0){
+                    continue;
+                }
+                String methodName = method.getName();
+                if(methodName.startsWith(METHOD_PREFIX_GET)
+                        || methodName.startsWith(METHOD_PREFIX_IS)) {
+                    if(method.getAnnotation(JSONField.class) != null){
+                        throw new UnsupportedOperationException("getBeanMethod JSONField Annotation Not Handled, Use toJSON");
+                    }
+                    methods.add(method);
+                }
+            }
+            methodsCache.put(key, methods);
+        }
+        return methods;
+    }
+
+
+
+    private static  final List<Field> getBeanFields(String key, Class targetClass){
+        List<Field> fieldList = fieldsCache.get(key);
+        if(fieldList == null) {
+            Field[] fields = targetClass.getFields();
+            fieldList = new ArrayList<>(fields.length);
+            for(Field field : fields){
+                if((field.getModifiers() & Modifier.STATIC) != 0){
+                    continue;
+                }
+                if(field.getAnnotation(JSONField.class) != null){
+                    throw new UnsupportedOperationException("getBeanMethod JSONField Annotation Not Handled, Use toJSON");
+                }
+                fieldList.add(field);
+            }
+            fieldsCache.put(key, fieldList);
+        }
+        return  fieldList;
+    }
+
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/wson/WsonUtils.java b/android/sdk/src/main/java/org/apache/weex/wson/WsonUtils.java
new file mode 100644
index 0000000..edd1a15
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/wson/WsonUtils.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.weex.wson;
+
+import org.apache.weex.utils.WXLogUtils;
+
+/**
+ * Created by furture on 2018/5/17.
+ */
+
+public class WsonUtils {
+    /**
+     * total entry, with wson support, always parse json
+     * */
+    public static final Object parseWson(byte[] data){
+        if(data == null){
+            return  null;
+        }
+        try{
+            return  Wson.parse(data);
+        }catch (Exception e){
+            WXLogUtils.e("weex wson parse error ", e);
+            return  null;
+        }
+    }
+
+    public static final byte[] toWson(Object data){
+        if(data == null){
+            return  null;
+        }
+        try{
+            return  Wson.toWson(data);
+        }catch (Exception e){
+            WXLogUtils.e("weex wson to wson error ", e);
+            return  null;
+        }
+    }
+}
diff --git a/android/sdk/src/test/java/com/taobao/weex/TestActivity.java b/android/sdk/src/test/java/com/taobao/weex/TestActivity.java
deleted file mode 100644
index 66b305e..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/TestActivity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.app.Activity;
-/**
- * Created by sospartan on 7/27/16.
- */
-public   class TestActivity extends Activity {
-  public  void test(){
-    //
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/TestApplication.java b/android/sdk/src/test/java/com/taobao/weex/TestApplication.java
deleted file mode 100644
index 9ca09d9..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/TestApplication.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import android.app.Application;
-
-/**
- * Created by sospartan on 7/21/16.
- */
-public class TestApplication extends Application {
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/WXSDKEngineTest.java b/android/sdk/src/test/java/com/taobao/weex/WXSDKEngineTest.java
deleted file mode 100644
index 0864653..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/WXSDKEngineTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import com.taobao.weex.bridge.WXBridgeManagerTest;
-import com.taobao.weex.common.TestModule;
-import com.taobao.weex.common.TestModuleFactory;
-import com.taobao.weex.ui.component.TestComponent;
-import com.taobao.weex.ui.component.WXComponent;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 7/20/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-@PrepareForTest({})
-public class WXSDKEngineTest {
-
-  @Before
-  public void setUp() throws Exception {
-
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    WXBridgeManagerTest.getLooper().idle();
-  }
-
-  @Test
-  public void testInit() throws Exception {
-    assertFalse(WXSDKEngine.isInitialized());
-    WXSDKEngine.initialize(RuntimeEnvironment.application,null);
-
-    new Thread(){
-      public void run(){
-        try {
-          Thread.sleep(60000);
-          assertTrue(WXSDKEngine.isInitialized());
-        } catch (InterruptedException e) { }
-      }
-    }.start();
-
-
-    //keep compatible
-    WXSDKEngine.init(RuntimeEnvironment.application);
-    WXSDKEngine.init(RuntimeEnvironment.application,null);
-    WXSDKEngine.init(RuntimeEnvironment.application,null,null);
-    WXSDKEngine.init(RuntimeEnvironment.application,null,null,null,null);
-  }
-
-  @Test
-  public void testRegisterComponent() throws Exception {
-    assertFalse(WXSDKEngine.registerComponent(null,(Class<? extends WXComponent>) null,true));
-    assertTrue(WXSDKEngine.registerComponent("test", TestComponent.class,true));
-    assertTrue(WXSDKEngine.registerComponent("test1",TestComponent.class));
-    assertTrue(WXSDKEngine.registerComponent(TestComponent.class,false,"testA","testB","testC"));
-    Map<String,Object> compInfo = new HashMap<>();
-    assertFalse(WXSDKEngine.registerComponent(compInfo,TestComponent.class));
-  }
-
-  @Test
-  public void testRegisterModule() throws Exception {
-    assertTrue(WXSDKEngine.registerModule("test", TestModule.class));
-    assertFalse(WXSDKEngine.registerModule(null,TestModule.class));
-    assertFalse(WXSDKEngine.registerModule("test",null));
-
-    assertFalse(WXSDKEngine.registerModuleWithFactory(null,new TestModuleFactory(TestModule.class),true));
-    assertTrue(WXSDKEngine.registerModuleWithFactory("test1",new TestModuleFactory(TestModule.class),true));
-  }
-
-
-  @Test
-  public void testRegisterDomObject() throws Exception {
-    assertFalse(WXSDKEngine.registerDomObject("test",null));
-    assertFalse(WXSDKEngine.registerDomObject("", TestDomObject.class));
-    assertTrue(WXSDKEngine.registerDomObject("test",TestDomObject.class));
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/WXSDKInstanceTest.java b/android/sdk/src/test/java/com/taobao/weex/WXSDKInstanceTest.java
deleted file mode 100644
index 6be97ae..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/WXSDKInstanceTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import static org.junit.Assert.assertEquals;
-import static org.powermock.api.mockito.PowerMockito.mock;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.when;
-
-import android.view.View;
-import android.widget.FrameLayout;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.bridge.WXBridgeManagerTest;
-import com.taobao.weex.common.WXPerformance;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.dom.WXDomManagerTest;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXComponentFactory;
-import com.taobao.weex.ui.component.WXDivTest;
-import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.WXFileUtils;
-import com.taobao.weex.utils.WXSoInstallMgrSdk;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLooper;
-
-
-/**
- * Created by sospartan on 7/27/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19,manifest = Config.NONE)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-@PrepareForTest({WXFileUtils.class,WXSoInstallMgrSdk.class})
-public class WXSDKInstanceTest {
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-
-  public static WXSDKInstance createInstance(){
-    WXSDKInstance instance =  new WXSDKInstance(Robolectric.setupActivity(TestActivity.class),"1");
-    final FrameLayout container = new FrameLayout(instance.getContext());
-    instance.registerRenderListener(new IWXRenderListener() {
-      @Override
-      public void onViewCreated(WXSDKInstance instance, View view) {
-        container.addView(view);
-      }
-
-      @Override
-      public void onRenderSuccess(WXSDKInstance instance, int width, int height) {
-
-      }
-
-      @Override
-      public void onRefreshSuccess(WXSDKInstance instance, int width, int height) {
-
-      }
-
-      @Override
-      public void onException(WXSDKInstance instance, String errCode, String msg) {
-
-      }
-    });
-    instance.mContext = Robolectric.setupActivity(TestActivity.class);
-
-    return instance;
-  }
-
-  public static void setupRoot(WXSDKInstance instance){
-
-    WXDomObject domObject = new WXDomObject();
-    WXVContainer comp = (WXVContainer) WXComponentFactory.newInstance(instance, domObject, null);
-
-    WXComponent root = WXDivTest.create(comp);
-    comp.addChild(root);
-    comp.createView();
-
-    instance.onCreateFinish();
-    ShadowLooper.idleMainLooper();
-  }
-
-  WXSDKInstance mInstance;
-
-  @Before
-  public void setup() throws Exception {
-    mockStatic(WXSoInstallMgrSdk.class);
-    when(WXSoInstallMgrSdk.initSo("weexv8", 1, null)).thenReturn(true);
-    WXSDKEngine.initialize(RuntimeEnvironment.application,new InitConfig.Builder().build());
-    mInstance = createInstance();
-    WXBridgeManagerTest.getLooper().idle();
-
-    mockStatic(WXFileUtils.class);
-    when(WXFileUtils.loadAsset(null,null)).thenReturn("{}");
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    WXBridgeManagerTest.getLooper().idle();
-    WXDomManagerTest.getLooper().idle();
-    mInstance.destroy();
-  }
-
-
-  @Test
-  public void testRender() throws Exception {
-    assertEquals(WXFileUtils.loadAsset(null,null),"{}");
-
-    mInstance.render("{}",null,null,null);
-
-  }
-
-  @Test
-  public void testSetSize() throws Exception {
-    setupRoot(mInstance);
-    mInstance.setSize(10,10);
-  }
-
-  @Test
-  public void testRenderEvent() throws Exception {
-    mInstance.onRenderError("test","test");
-    mInstance.onRenderSuccess(10,10);
-  }
-
-  @Test
-  public void testRenderByUrl() throws Exception {
-    mInstance.renderByUrl(WXPerformance.DEFAULT,"file:///test",null,null,100,100, WXRenderStrategy.APPEND_ASYNC);
-    mInstance.renderByUrl(WXPerformance.DEFAULT,"http://taobao.com",null,null,100,100, WXRenderStrategy.APPEND_ASYNC);
-  }
-
-  @Test
-  public void testGlobalEvent() throws Exception {
-    mInstance.addEventListener(null,null);
-    mInstance.addEventListener(null,"");
-    mInstance.addEventListener("",null);
-
-    mInstance.addEventListener("test","123");
-    mInstance.fireGlobalEventCallback("test",null);
-    mInstance.removeEventListener("test");
-    mInstance.removeEventListener("test","123");
-  }
-
-  @Test
-  public void testFireEvent() throws Exception {
-    mInstance.fireEvent("1","test");
-    Map<String,Object> params = new HashMap<>();
-    params.put("arg1",null);
-    params.put("arg2",123);
-    mInstance.fireEvent("1","test",params);
-
-    Map<String,Object> domChange = new HashMap<>();
-    domChange.put("attr1","123");
-    mInstance.fireEvent("1","test",params,domChange);
-  }
-
-
-  @Test
-  public void testOnActivityLifecycle() throws Exception {
-    mInstance.registerActivityStateListener(mock(IWXActivityStateListener.class));
-    mInstance.onActivityCreate();
-    mInstance.onActivityStart();
-    mInstance.onActivityResume();
-    mInstance.onActivityPause();
-    mInstance.onActivityStop();
-  }
-
-  @Test
-  public void testOnJSException() throws Exception {
-    mInstance.onJSException(null,null,null);
-    mInstance.onJSException("100","test","some error");
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/WXSDKManagerTest.java b/android/sdk/src/test/java/com/taobao/weex/WXSDKManagerTest.java
deleted file mode 100644
index ae6442d..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/WXSDKManagerTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex;
-
-import com.taobao.weex.ui.WXRenderManager;
-import org.junit.After;
-import org.junit.Before;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 8/30/16.
- */
-public class WXSDKManagerTest {
-
-  public static void setRenderManager(WXRenderManager rm){
-    WXSDKManager.initInstance(rm);
-  }
-
-  public static void setInstance(WXSDKManager m){
-    WXSDKManager.setInstance(m);
-  }
-
-  @Before
-  public void setUp() throws Exception {
-
-  }
-
-  @After
-  public void tearDown() throws Exception {
-
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/adapter/DefaultUriAdapterTest.java b/android/sdk/src/test/java/com/taobao/weex/adapter/DefaultUriAdapterTest.java
deleted file mode 100644
index 3c4d84b..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/adapter/DefaultUriAdapterTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.adapter;
-
-import android.net.Uri;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.WXSDKManagerTest;
-import com.taobao.weex.common.WXRenderStrategy;
-import com.taobao.weex.common.WXRequest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.mockito.internal.util.MockUtil;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.assertEquals;
-
-
-/**
- * Created by sospartan on 21/11/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
-public class DefaultUriAdapterTest {
-  URIAdapter adapter;
-  WXSDKInstance instance;
-
-  @Before
-  public void setup() {
-    WXEnvironment.sApplication = RuntimeEnvironment.application;
-    WXSDKManager wxsdkManager = WXSDKManager.getInstance();
-    if (!new MockUtil().isSpy(wxsdkManager)) {
-      WXSDKManager spy = Mockito.spy(wxsdkManager);
-      WXSDKManagerTest.setInstance(spy);
-      Mockito.when(spy.getIWXHttpAdapter()).thenReturn(new IWXHttpAdapter() {
-        @Override
-        public void sendRequest(WXRequest request, OnHttpListener listener) {
-          //do nothing.
-        }
-      });
-    }
-
-    adapter = new DefaultUriAdapter();
-    instance = WXSDKInstanceTest.createInstance();
-  }
-
-  @Test
-  public void testRewrite() throws Exception {
-
-    final String host = "http://127.0.0.1";
-    final String base = host + "/test/123/";
-    final String bundleWithSlash = base + "?arg=value";
-    final String bundle = base + "bundle.js?arg=value";
-
-
-    instance.renderByUrl("", bundle, null, null, 0, 0, WXRenderStrategy.APPEND_ONCE);
-    testRelative(host, base, bundle);
-    instance.renderByUrl("", bundleWithSlash, null, null, 0, 0, WXRenderStrategy.APPEND_ONCE);
-    testRelative(host, base, bundleWithSlash);
-  }
-
-  private void testRelative(String host, String baseWithSlash, String bundleUrl) {
-    Uri uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse("./456"));
-    assertEquals(Uri.parse(baseWithSlash + "./456"), uri);
-
-    uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse("../456"));
-    assertEquals(Uri.parse(baseWithSlash + "../456"), uri);
-
-
-    uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse("./456?k=v"));
-    assertEquals(Uri.parse(baseWithSlash + "./456?k=v"), uri);
-
-    uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse("./456?k=v&k2=v2"));
-    assertEquals(Uri.parse(baseWithSlash + "./456?k=v&k2=v2"), uri);
-
-    uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse("./456?k=v#flagment"));
-    assertEquals(Uri.parse(baseWithSlash + "./456?k=v#flagment"), uri);
-
-    uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse("//test.com/test/test2"));
-    assertEquals(Uri.parse("http://test.com/test/test2"), uri);
-
-    uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse("/test2"));
-    assertEquals(Uri.parse(host + "/test2"), uri);
-
-    uri = adapter.rewrite(instance, URIAdapter.IMAGE, Uri.parse(""));
-    assertEquals(Uri.parse(bundleUrl), uri);
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/appfram/clipboard/WXClipboardModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/appfram/clipboard/WXClipboardModuleTest.java
deleted file mode 100644
index 4f2de36..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/appfram/clipboard/WXClipboardModuleTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.clipboard;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.bridge.JSCallback;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 27/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXClipboardModuleTest {
-
-  WXClipboardModule module;
-
-  @Before
-  public void setUp() throws Exception {
-    module = new WXClipboardModule();
-    module.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-
-  }
-
-  @Test
-  public void testSetString() throws Exception {
-    module.setString("test");
-  }
-
-  @Test
-  public void testGetString() throws Exception {
-
-    JSCallback mock = Mockito.mock(JSCallback.class);
-    module.getString(mock);
-    Mockito.verify(mock,Mockito.times(1)).invoke(Mockito.anyObject());
-
-    testSetString();
-
-    mock = Mockito.mock(JSCallback.class);
-    module.getString(mock);
-    Mockito.verify(mock,Mockito.times(1)).invoke(Mockito.anyObject());
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/appfram/navigator/WXNavigatorModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/appfram/navigator/WXNavigatorModuleTest.java
deleted file mode 100644
index 9084adc..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/appfram/navigator/WXNavigatorModuleTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.navigator;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.*;
-import static org.mockito.Mockito.*;
-
-/**
- * Created by sospartan on 7/28/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*","org.json.*" })
-@PrepareForTest(WXSDKEngine.class)
-public class WXNavigatorModuleTest {
-
-  WXNavigatorModule module;
-  JSCallback callback;
-
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-
-  @Before
-  public void setUp() throws Exception {
-    mockStatic(WXSDKEngine.class);
-    callback = Mockito.mock(JSCallback.class);
-
-
-    module = new WXNavigatorModule();
-    module.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-  }
-
-  private void mockSetter(){
-    when(WXSDKEngine.getActivityNavBarSetter()).thenReturn(new IActivityNavBarSetter() {
-      @Override
-      public boolean push(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean pop(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean setNavBarRightItem(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean clearNavBarRightItem(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean setNavBarLeftItem(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean clearNavBarLeftItem(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean setNavBarMoreItem(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean clearNavBarMoreItem(String param) {
-        return true;
-      }
-
-      @Override
-      public boolean setNavBarTitle(String param) {
-        return true;
-      }
-    });
-  }
-
-  @Test
-  public void testPush() throws Exception {
-    module.push("{}",callback);
-    module.push("{'url':'kdkdkdkdkd'}",callback);
-    mockSetter();
-    module.push("{}",callback);
-  }
-
-
-  @Test
-  public void testPop() throws Exception {
-    mockSetter();
-    module.pop("{}",callback);
-  }
-
-  @Test
-  public void testSetNavBarRightItem() throws Exception {
-    mockSetter();
-    module.setNavBarRightItem("{}",callback);
-  }
-
-  @Test
-  public void testClearNavBarRightItem() throws Exception {
-    mockSetter();
-    module.clearNavBarRightItem("{}",callback);
-  }
-
-  @Test
-  public void testSetNavBarLeftItem() throws Exception {
-    mockSetter();
-    module.setNavBarLeftItem("{}",callback);
-  }
-
-  @Test
-  public void testClearNavBarLeftItem() throws Exception {
-    mockSetter();
-    module.clearNavBarLeftItem("{}",callback);
-  }
-
-  @Test
-  public void testSetNavBarMoreItem() throws Exception {
-    mockSetter();
-    module.setNavBarMoreItem("{}",callback);
-  }
-
-  @Test
-  public void testClearNavBarMoreItem() throws Exception {
-    mockSetter();
-    module.clearNavBarMoreItem("{}",callback);
-  }
-
-  @Test
-  public void testSetNavBarTitle() throws Exception {
-    mockSetter();
-    module.setNavBarTitle("{}",callback);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/appfram/storage/DefaultWXStorageTest.java b/android/sdk/src/test/java/com/taobao/weex/appfram/storage/DefaultWXStorageTest.java
deleted file mode 100644
index fae69b8..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/appfram/storage/DefaultWXStorageTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import static org.mockito.Mockito.anyMapOf;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 7/28/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-public class DefaultWXStorageTest {
-
-  @Mock
-  WXSQLiteOpenHelper supplier;
-  @Mock
-  IWXStorageAdapter.OnResultReceivedListener listener;
-  DefaultWXStorage storage;
-
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-
-  @Before
-  public void setup() throws Exception{
-    MockitoAnnotations.initMocks(this);
-    storage = new DefaultWXStorage(RuntimeEnvironment.application);
-    mockStatic(WXSQLiteOpenHelper.class);
-    whenNew(WXSQLiteOpenHelper.class)
-            .withArguments(RuntimeEnvironment.application)
-            .thenReturn(supplier);
-  }
-
-
-  @Test
-  public void testSetItem() throws Exception {
-    storage.setItem("","",listener);
-
-    verify(listener,timeout(3000).times(1)).onReceived(anyMapOf(String.class,Object.class));
-    storage.close();
-  }
-
-  @Test
-  public void testGetItem() throws Exception {
-    storage.getItem("",listener);
-
-    verify(listener,timeout(3000).times(1)).onReceived(anyMapOf(String.class,Object.class));
-    storage.close();
-  }
-
-  @Test
-  public void testRemoveItem() throws Exception {
-    storage.removeItem("",listener);
-
-    verify(listener,timeout(3000).times(1)).onReceived(anyMapOf(String.class,Object.class));
-    storage.close();
-  }
-
-  @Test
-  public void testLength() throws Exception {
-    storage.length(listener);
-
-    verify(listener,timeout(3000).times(1)).onReceived(anyMapOf(String.class,Object.class));
-    storage.close();
-  }
-
-  @Test
-  public void testGetAllKeys() throws Exception {
-    storage.getAllKeys(listener);
-
-    verify(listener,timeout(3000).times(1)).onReceived(anyMapOf(String.class,Object.class));
-    storage.close();
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/appfram/storage/WXStorageModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/appfram/storage/WXStorageModuleTest.java
deleted file mode 100644
index 1ff7c89..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/appfram/storage/WXStorageModuleTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.appfram.storage;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 7/28/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-@PrepareForTest(WXBridgeManager.class)
-public class WXStorageModuleTest {
-
-
-  WXStorageModule module;
-  JSCallback callback;
-
-  @Before
-  public void setUp() throws Exception {
-    module = new WXStorageModule();
-    module.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-    module.mStorageAdapter = new IWXStorageAdapter() {
-      @Override
-      public void setItem(String key, String value, OnResultReceivedListener listener) {
-        Map<String, Object> data = StorageResultHandler.setItemResult(true);
-        listener.onReceived(data);
-      }
-
-      @Override
-      public void getItem(String key, OnResultReceivedListener listener) {
-        Map<String, Object> data = StorageResultHandler.setItemResult(true);
-        listener.onReceived(data);
-      }
-
-      @Override
-      public void removeItem(String key, OnResultReceivedListener listener) {
-        Map<String, Object> data = StorageResultHandler.setItemResult(true);
-        listener.onReceived(data);
-      }
-
-      @Override
-      public void length(OnResultReceivedListener listener) {
-        Map<String, Object> data = StorageResultHandler.setItemResult(true);
-        listener.onReceived(data);
-      }
-
-      @Override
-      public void getAllKeys(OnResultReceivedListener listener) {
-        Map<String, Object> data = StorageResultHandler.setItemResult(true);
-        listener.onReceived(data);
-      }
-
-      @Override
-      public void setItemPersistent(String key, String value, OnResultReceivedListener listener) {
-
-      }
-
-      @Override
-      public void close() {
-
-      }
-    };
-    callback = Mockito.mock(JSCallback.class);
-  }
-
-  @Test
-  public void testSetItem() throws Exception {
-    module.setItem("","",callback);
-    verify(callback,times(1)).invoke(any());
-
-  }
-
-  @Test
-  public void testGetItem() throws Exception {
-    module.getItem("",callback);
-    verify(callback,times(1)).invoke(any());
-  }
-
-  @Test
-  public void testRemoveItem() throws Exception {
-    module.removeItem("",callback);
-    verify(callback,times(1)).invoke(any());
-  }
-
-  @Test
-  public void testLength() throws Exception {
-    module.length(callback);
-    verify(callback,times(1)).invoke(any());
-  }
-
-  @Test
-  public void testGetAllKeys() throws Exception {
-    module.getAllKeys(callback);
-    verify(callback,times(1)).invoke(any());
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/bridge/WXBridgeManagerTest.java b/android/sdk/src/test/java/com/taobao/weex/bridge/WXBridgeManagerTest.java
deleted file mode 100644
index 61a3f14..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/bridge/WXBridgeManagerTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import static junit.framework.Assert.assertNotNull;
-
-import android.os.Handler;
-import android.os.Message;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.InitConfig;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.WXSDKManagerTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXJSBridgeMsgType;
-import com.taobao.weex.ui.WXRenderManager;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLooper;
-
-
-/**
- * Created by lixinke on 16/2/24.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-@PrepareForTest(WXModuleManager.class)
-public class WXBridgeManagerTest {
-
-  WXSDKInstance instance;
-
-  public static ShadowLooper getLooper() {
-    WXBridgeManager bridgeManager = WXBridgeManager.getInstance();
-    Handler handler = bridgeManager.mJSHandler;
-    return Shadows.shadowOf(handler.getLooper());
-  }
-
-  public static void setBridgeManager(WXBridgeManager bridge) {
-    WXBridgeManager.mBridgeManager = bridge;
-  }
-
-  private WXBridgeManager getInstance() {
-    return WXBridgeManager.getInstance();
-  }
-
-  @Before
-  public void setUp() throws Exception {
-    WXSDKEngine.initialize(RuntimeEnvironment.application,new InitConfig.Builder().build());
-    instance = WXSDKInstanceTest.createInstance();
-    WXRenderManager rednerManager = new WXRenderManager();
-    rednerManager.registerInstance(instance);//
-    WXSDKManagerTest.setRenderManager(rednerManager);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    getLooper().idle();
-    getInstance().destroy();
-  }
-
-  @Test
-  public void testGetInstance() throws Exception {
-    WXBridgeManager instance = WXBridgeManager.getInstance();
-    assertNotNull(instance);
-  }
-
-  @Test
-  public void testRestart() throws Exception {
-    getInstance().restart();
-  }
-
-  @Test
-  public void testSetStackTopInstance() throws Exception {
-    getInstance().setStackTopInstance("");
-  }
-
-  @Test
-  public void testCallNative() throws Exception {
-    getInstance()
-        .callNative(instance.getInstanceId(),
-            "[{\"module\":\"testModule\",\"method\":\"test\"}]",
-            null);
-
-    getInstance()
-        .callNative(instance.getInstanceId(),
-            "[{\"module\":\""+WXDomModule.WXDOM+"\",\"method\":\"test\"}]",
-            null);
-
-  }
-
-  @Test
-  public void testInitScriptsFramework() throws Exception {
-    getInstance().initScriptsFramework("");
-  }
-
-  @Test
-  public void testFireEvent() throws Exception {
-    getInstance().fireEvent(instance.getInstanceId(),"100", Constants.Event.CLICK,null,null);
-  }
-
-  @Test
-  public void testCallback() throws Exception {
-    getInstance().callbackJavascript(instance.getInstanceId(),"test",null,false);
-  }
-
-  @Test
-  public void testRefreshInstance() throws Exception {
-    getInstance().refreshInstance(instance.getInstanceId(),null);
-  }
-
-  @Test
-  public void testCreateInstance() throws Exception {
-    getInstance().createInstance(instance.getInstanceId(),"",null,null);
-  }
-
-  @Test
-  public void testDestroyInstance() throws Exception {
-    getInstance().destroyInstance(instance.getInstanceId());
-  }
-
-  @Test
-  public void testHandleMessage() throws Exception {
-    int[] msgs = {
-        WXJSBridgeMsgType.INIT_FRAMEWORK,
-        WXJSBridgeMsgType.CALL_JS_BATCH,
-        WXJSBridgeMsgType.SET_TIMEOUT,
-        WXJSBridgeMsgType.MODULE_INTERVAL,
-        WXJSBridgeMsgType.MODULE_TIMEOUT
-    };
-    Message msg = new Message();
-    for(int w:msgs) {
-      msg.what = w;
-      getInstance().handleMessage(msg);
-    }
-  }
-
-  @Test
-  public void testReportJSException() throws Exception {
-    getInstance().reportJSException(instance.getInstanceId(),"test","test exception");
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/bridge/WXBridgeTest.java b/android/sdk/src/test/java/com/taobao/weex/bridge/WXBridgeTest.java
deleted file mode 100644
index 13feaf6..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/bridge/WXBridgeTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 27/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXBridgeTest {
-
-  WXBridge bridge;
-
-  @Before
-  public void setUp() throws Exception {
-    bridge = new WXBridge();
-  }
-
-  @Test
-  public void testCallNative() throws Exception {
-    bridge.callNative("1","{}","100");
-  }
-
-  @Test
-  public void testCallAddElement() throws Exception {
-    bridge.callAddElement("1","1","{}","0","100");
-  }
-
-
-  @After
-  public void tearDown() throws Exception {
-
-  }
-
-  @Test
-  public void testReportJSException() throws Exception {
-    bridge.reportJSException("1","test","some exception");
-  }
-
-  @Test
-  public void testSetTimeoutNative() throws Exception {
-    bridge.setTimeoutNative("100","1024");
-  }
-
-  @Test
-  public void testSetJSFrmVersion() throws Exception {
-    bridge.setJSFrmVersion("v0.1");
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/bridge/WXHashMapTest.java b/android/sdk/src/test/java/com/taobao/weex/bridge/WXHashMapTest.java
deleted file mode 100644
index 71638ae..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/bridge/WXHashMapTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.util.Stack;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class,manifest = Config.NONE)
-public class WXHashMapTest {
-	private WXHashMap<String, String> mWXHashMap = new WXHashMap<>();
-
-	@Before
-	public void setUp() throws Exception {
-		mWXHashMap.clear();
-	}
-
-	@Test
-	public void testPutKV() {
-		mWXHashMap.put("one", "1");
-		assertEquals("1", mWXHashMap.get("one"));
-	}
-
-	@Test
-	public void testRemoveObject() {
-		mWXHashMap.put("one", "1");
-		mWXHashMap.remove("one");
-		assertEquals(0, mWXHashMap.size());
-	}
-
-	@Test
-	public void testRemoveFromMapAndStack() {
-		mWXHashMap.put("one","1");
-		mWXHashMap.removeFromMapAndStack("one");
-		assertEquals(true,mWXHashMap.getInstanceStack().empty());
-	}
-
-	@Test
-	public void testGetStackTopInstanceId() {
-		mWXHashMap.setStackTopInstance("123456");
-		mWXHashMap.setStackTopInstance("654321");
-		String id=mWXHashMap.getStackTopInstanceId();
-		assertEquals("654321",id);
-	}
-
-	@Test
-	public void testSetStackTopInstance() {
-		mWXHashMap.setStackTopInstance("123456");
-		int size=mWXHashMap.getInstanceStack().size();
-		assertEquals(1,size);
-	}
-
-	@Test
-	public void testGetInstanceStack() {
-		Stack<String> instance= mWXHashMap.getInstanceStack();
-		assertNotNull(instance);
-	}
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/bridge/WXModuleManagerTest.java b/android/sdk/src/test/java/com/taobao/weex/bridge/WXModuleManagerTest.java
deleted file mode 100644
index c4c92d8..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/bridge/WXModuleManagerTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.bridge;
-
-import com.alibaba.fastjson.JSONArray;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.InitConfig;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.TestModule;
-import com.taobao.weex.common.TypeModuleFactory;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 8/31/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class)
-public class WXModuleManagerTest {
-
-  WXSDKInstance instance;
-
-  @Before
-  public void setUp() throws Exception {
-    WXSDKEngine.initialize(RuntimeEnvironment.application,new InitConfig.Builder().build());
-    instance = WXSDKInstanceTest.createInstance();
-    WXModuleManager.registerModule("test",null,false);
-    WXModuleManager.registerModule("test1",new TypeModuleFactory<>(TestModule.class),true);
-    WXModuleManager.registerModule("test2",new TypeModuleFactory<>(TestModule.class),false);
-    WXBridgeManagerTest.getLooper().idle();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-
-  }
-
-  @Test
-  public void testCallModuleMethod() throws Exception {
-    WXModuleManager.callModuleMethod(instance.getInstanceId(),"test1","testMethod",null);
-    WXModuleManager.callModuleMethod(instance.getInstanceId(),"test2","testMethod",null);
-  }
-
-  @Test
-  public void testCallModuleMethod2() throws Exception {
-    JSONArray args = new JSONArray();
-    args.add("testarg");
-    WXModuleManager.callModuleMethod(instance.getInstanceId(),"test1","testMethod",args);
-  }
-
-  @Test
-  public void testCallModuleMethod3() throws Exception {
-    JSONArray args = new JSONArray();
-    args.add("testarg");
-    args.add(null);
-    WXModuleManager.callModuleMethod(instance.getInstanceId(),"test1","testCallbackMethod",args);
-  }
-
-  @Test
-  public void testCallModuleMethod4() throws Exception {
-    JSONArray args = new JSONArray();
-    args.add("testarg");
-    args.add("testcallbackId");
-    WXModuleManager.callModuleMethod(instance.getInstanceId(),"test1","testCallbackMethod",args);
-  }
-
-  @Test
-  public void testDestroyInstanceModules() throws Exception {
-    testCallModuleMethod();//module instance is lazy create.
-    WXModuleManager.destroyInstanceModules(instance.getInstanceId());
-  }
-
-  @Test
-  public void testReload() throws Exception {
-    WXModuleManager.reload();
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/common/TestModule.java b/android/sdk/src/test/java/com/taobao/weex/common/TestModule.java
deleted file mode 100644
index b1158d4..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/common/TestModule.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.JSCallback;
-
-/**
- * Created by sospartan on 7/27/16.
- */
-public class TestModule extends WXSDKEngine.DestroyableModule {
-
-  @JSMethod
-  public void testMethod(String arg){
-
-  }
-
-  @JSMethod(uiThread=true)
-  public void testCallbackMethod(String arg, JSCallback callback){
-
-  }
-
-  @Override
-  public void destroy() {
-
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/common/TestModuleFactory.java b/android/sdk/src/test/java/com/taobao/weex/common/TestModuleFactory.java
deleted file mode 100644
index ae9fc65..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/common/TestModuleFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.bridge.ModuleFactory;
-
-import java.util.ArrayList;
-import java.util.Map;
-
-/**
- * Created by sospartan on 7/27/16.
- */
-public class TestModuleFactory extends WXSDKEngine.DestroyableModuleFactory<TestModule> {
-
-
-  public TestModuleFactory(Class<TestModule> clz) {
-    super(clz);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/common/WXModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/common/WXModuleTest.java
deleted file mode 100644
index 5860720..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/common/WXModuleTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.common;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 7/27/16.
- */
-public class WXModuleTest {
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/dom/WXAttrTest.java b/android/sdk/src/test/java/com/taobao/weex/dom/WXAttrTest.java
deleted file mode 100644
index c122418..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/dom/WXAttrTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import static com.taobao.weex.common.Constants.Name.IMAGE_QUALITY;
-import static com.taobao.weex.common.Constants.Name.SRC;
-import static com.taobao.weex.common.Constants.Name.VALUE;
-import static com.taobao.weex.common.Constants.Value.HIGH;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXImageSharpen;
-import com.taobao.weex.utils.WXViewUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class)
-public class WXAttrTest {
-
-  WXAttr attr;
-
-  @Before
-  public void setUp() throws Exception {
-    attr = new WXAttr();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    attr.clear();
-  }
-
-  @Test
-  public void testGetValue() throws Exception {
-    assertEquals(null,WXAttr.getValue(attr));
-
-    attr.put(VALUE,"test");
-
-    assertEquals("test",WXAttr.getValue(attr));
-  }
-
-  @Test
-  public void testGetImageQuality() throws Exception {
-    assertEquals(WXImageQuality.AUTO,attr.getImageQuality());
-
-    attr.put(IMAGE_QUALITY,HIGH);
-    assertEquals(WXImageQuality.HIGH,attr.getImageQuality());
-  }
-
-  @Test
-  public void testGetImageSharpen() throws Exception {
-    assertEquals(WXImageSharpen.UNSHARPEN,attr.getImageSharpen());
-
-  }
-
-  @Test
-  public void testGetImageSrc() throws Exception {
-    assertEquals(null,attr.getImageSrc());
-
-    attr.put(SRC,"test");
-    assertEquals("test",attr.getImageSrc());
-  }
-
-  @Test
-  public void testShowIndicators() throws Exception {
-    assertEquals(true,attr.showIndicators());
-  }
-
-  @Test
-  public void testAutoPlay() throws Exception {
-    assertEquals(false,attr.autoPlay());
-  }
-
-  @Test
-  public void testGetScope() throws Exception {
-    assertEquals(null,attr.getScope());
-  }
-
-  @Test
-  public void testGetLoadMoreRetry() throws Exception {
-    assertEquals(null,attr.getLoadMoreRetry());
-  }
-
-  @Test
-  public void testGetLoadMoreOffset() throws Exception {
-    assertEquals(null,attr.getLoadMoreOffset());
-  }
-
-  @Test
-  public void testGetIsRecycleImage() throws Exception {
-    assertEquals(true,attr.getIsRecycleImage());
-  }
-
-  @Test
-  public void testGetScrollDirection() throws Exception {
-    assertEquals("vertical",attr.getScrollDirection());
-  }
-
-  @Test
-  public void testGetElevation() {
-    int elevation = 100, viewPortW = 750;
-
-    attr.put(Constants.Name.ELEVATION, elevation);
-    assertThat(attr.getElevation(viewPortW),
-               is(WXViewUtils.getRealSubPxByWidth(elevation, viewPortW)));
-
-    attr.put(Constants.Name.ELEVATION, "");
-    assertThat(attr.getElevation(viewPortW), is(0f));
-
-    attr.put(Constants.Name.ELEVATION, "give me a NAN");
-    assertThat(attr.getElevation(viewPortW), is(Float.NaN));
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/dom/WXDomManagerTest.java b/android/sdk/src/test/java/com/taobao/weex/dom/WXDomManagerTest.java
deleted file mode 100644
index 261b5b7..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/dom/WXDomManagerTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.ui.WXRenderManager;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowLooper;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 8/31/16.
- */
-@RunWith(RobolectricTestRunner.class)
-public class WXDomManagerTest {
-
-  public static ShadowLooper getLooper() {
-    return Shadows.shadowOf(WXSDKManager.getInstance().getWXDomManager().mDomHandler.getLooper());
-  }
-
-  WXDomManager dm;
-  WXSDKInstance instance;
-
-  @Before
-  public void setUp() throws Exception {
-    WXRenderManager rm = new WXRenderManager();
-    instance =   WXSDKInstanceTest.createInstance();
-    rm.registerInstance(instance);
-    dm = new WXDomManager(rm);
-  }
-
-  @Test
-  public void testRemoveDomStatement() throws Exception {
-      dm.removeDomStatement(instance.getInstanceId());
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    getLooper().idle();
-    dm.destroy();
-  }
-
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/dom/WXDomStatementTest.java b/android/sdk/src/test/java/com/taobao/weex/dom/WXDomStatementTest.java
deleted file mode 100644
index 4bdd77a..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/dom/WXDomStatementTest.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.InitConfig;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.WXSDKManager;
-import com.taobao.weex.WXSDKManagerTest;
-import com.taobao.weex.bridge.WXBridgeManagerTest;
-import com.taobao.weex.ui.WXRenderManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLooper;
-
-/**
- * Created by sospartan on 8/29/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXDomStatementTest {
-
-  DOMActionContextImpl stmt;
-  WXRenderManager rednerManager;
-  WXSDKInstance instance;
-
-  @Before
-  public void setUp() throws Exception {
-    WXSDKEngine.initialize(RuntimeEnvironment.application,new InitConfig.Builder().build());
-    ShadowLooper looper = WXBridgeManagerTest.getLooper();
-    looper.idle();
-    ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
-    instance = WXSDKInstanceTest.createInstance();
-    rednerManager = new WXRenderManager();
-    rednerManager.registerInstance(instance);//
-    WXSDKManagerTest.setRenderManager(rednerManager);
-    stmt = new DOMActionContextImpl(instance.getInstanceId(),rednerManager );
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    stmt.destroy();
-  }
-
-  void createBody(){
-    JSONObject body = new JSONObject();
-    body.put("type","div");
-    body.put("ref",WXDomObject.ROOT);
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(), TestActions.body(body),true);
-  }
-
-  void addDom(JSONObject obj,String parentRef,int index){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.addDom(obj,parentRef,index),false);
-  }
-
-  void removeDom(String ref){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.remove(ref),false);
-  }
-
-  void updateAttrs(String ref,JSONObject data){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.updateAttr(ref,data),false);
-  }
-
-  void updateStyle(String ref,JSONObject data,boolean byPesudo){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.updateStyle(ref,data,byPesudo),false);
-  }
-
-  void moveDom(String ref,String parent,int index){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.moveDom(ref,parent,index),false);
-  }
-
-  private void scrollToDom(String s, JSONObject o) {
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.scrollTo(s,o),false);
-  }
-
-  private void addEvent(String ref,String event){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.addEvent(ref,event),false);
-  }
-
-  private void removeEvent(String ref,String event){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.removeEvent(ref,event),false);
-  }
-
-  private void updateFinish(){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.updateFinish(),false);
-  }
-
-  private void createFinish(){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.createFinish(),false);
-  }
-
-  private void refreshFinish(){
-    WXSDKManager.getInstance().getWXDomManager().executeAction(instance.getInstanceId(),TestActions.refreshFinish(),false);
-  }
-
-  @Test
-  public void testCustomDomObject() throws Exception {
-    WXDomObject root = new TestDomObject();
-    root.add(new WXListDomObject(),0);
-    root.add(new WXScrollerDomObject(),0);
-    root.add(new WXTextDomObject(),0);
-    root.add(new WXSwitchDomObject(),0);
-    root.add(new TextAreaEditTextDomObject(),0);
-    stmt.layout(root);
-    root.traverseTree(ApplyStyleConsumer.getInstance());
-  }
-
-  @Test
-  public void testCreateBody() throws Exception {
-    createBody();
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testAddDom() throws Exception {
-    createBody();
-
-    JSONObject obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-
-    addDom(obj,WXDomObject.ROOT,0);
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testMoveDom() throws Exception {
-    createBody();
-    JSONObject obj;
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","101");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    moveDom("100",WXDomObject.ROOT,1);
-    stmt.batch();
-  }
-
-  @Test
-  public void testRemoveDom() throws Exception {
-    createBody();
-    JSONObject obj;
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","101");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    removeDom("101");
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testUpdateAttrs() throws Exception {
-    createBody();
-    JSONObject obj;
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-    addDom(obj,WXDomObject.ROOT,0);
-
-
-    updateAttrs("100",new JSONObject());
-    updateAttrs("100",null);
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testUpdateStyle() throws Exception {
-    createBody();
-    JSONObject obj;
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    updateStyle("100",new JSONObject(),false);
-    updateStyle("100",null,false);
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testAddEvent() throws Exception {
-    createBody();
-    JSONObject obj;
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    addEvent("100","click");
-    addEvent("100",null);
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testRemoveEvent() throws Exception {
-    createBody();
-    JSONObject obj;
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    removeEvent("100",null);
-    addEvent("100","click");
-    removeEvent("100","click");
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testScrollToDom() throws Exception {
-    createBody();
-    JSONObject obj;
-    obj = new JSONObject();
-    obj.put("type","div");
-    obj.put("ref","100");
-    addDom(obj,WXDomObject.ROOT,0);
-
-    scrollToDom("100",null);
-    stmt.batch();
-  }
-
-
-
-  @Test
-  public void testCreateFinish() throws Exception {
-    createBody();
-    createFinish();
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testRefreshFinish() throws Exception {
-    createBody();
-    refreshFinish();
-
-    stmt.batch();
-  }
-
-  @Test
-  public void testUpdateFinish() throws Exception {
-    createBody();
-
-    updateFinish();
-    stmt.batch();
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/dom/WXStyleTest.java b/android/sdk/src/test/java/com/taobao/weex/dom/WXStyleTest.java
deleted file mode 100644
index f6641d4..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/dom/WXStyleTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import android.graphics.Typeface;
-
-import com.taobao.weex.common.Constants;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.hamcrest.CoreMatchers.*;
-
-
-/**
- * Description:
- *
- * Created by rowandjj(chuyi)<br/>
- */
-
-public class WXStyleTest {
-    WXStyle style;
-
-    @Before
-    public void setUp() throws Exception {
-        style = new WXStyle();
-    }
-
-
-    @Test
-    public void testBlur() {
-        assertEquals(0,style.size());
-        assertEquals(null,style.getBlur());
-        style.put(Constants.Name.FILTER,"blur(5px)");
-        assertEquals("blur(5px)",style.getBlur());
-
-    }
-
-    @Test
-    public void testFontWeight(){
-        WXStyle none = new WXStyle();
-        assertThat(WXStyle.getFontWeight(none), is(Typeface.NORMAL));
-
-        WXStyle normal = new WXStyle();
-        normal.put(Constants.Name.FONT_WEIGHT, Constants.Value.NORMAL);
-        assertThat(WXStyle.getFontWeight(normal), is(Typeface.NORMAL));
-
-        WXStyle bold = new WXStyle();
-        bold.put(Constants.Name.FONT_WEIGHT, Constants.Value.BOLD);
-        assertThat(WXStyle.getFontWeight(bold), is(Typeface.BOLD));
-
-        WXStyle illegal = new WXStyle();
-        illegal.put(Constants.Name.FONT_WEIGHT, "f");
-        assertThat(WXStyle.getFontWeight(illegal), is(Typeface.NORMAL));
-
-        WXStyle number100 = new WXStyle();
-        number100.put(Constants.Name.FONT_WEIGHT, "100");
-        assertThat(WXStyle.getFontWeight(number100), is(Typeface.NORMAL));
-
-        WXStyle number200 = new WXStyle();
-        number200.put(Constants.Name.FONT_WEIGHT, "200");
-        assertThat(WXStyle.getFontWeight(number200), is(Typeface.NORMAL));
-
-        WXStyle number300 = new WXStyle();
-        number300.put(Constants.Name.FONT_WEIGHT, "300");
-        assertThat(WXStyle.getFontWeight(number300), is(Typeface.NORMAL));
-
-        WXStyle number400 = new WXStyle();
-        number400.put(Constants.Name.FONT_WEIGHT, "400");
-        assertThat(WXStyle.getFontWeight(number400), is(Typeface.NORMAL));
-
-        WXStyle number500 = new WXStyle();
-        number500.put(Constants.Name.FONT_WEIGHT, "500");
-        assertThat(WXStyle.getFontWeight(number500), is(Typeface.NORMAL));
-
-        WXStyle number600 = new WXStyle();
-        number600.put(Constants.Name.FONT_WEIGHT, "600");
-        assertThat(WXStyle.getFontWeight(number600), is(Typeface.BOLD));
-
-        WXStyle number700 = new WXStyle();
-        number700.put(Constants.Name.FONT_WEIGHT, "700");
-        assertThat(WXStyle.getFontWeight(number700), is(Typeface.BOLD));
-
-        WXStyle number800 = new WXStyle();
-        number800.put(Constants.Name.FONT_WEIGHT, "800");
-        assertThat(WXStyle.getFontWeight(number800), is(Typeface.BOLD));
-
-        WXStyle number900 = new WXStyle();
-        number900.put(Constants.Name.FONT_WEIGHT, "900");
-        assertThat(WXStyle.getFontWeight(number900), is(Typeface.BOLD));
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        style.clear();
-    }
-
-    @Test
-    public void testPesudoParsing() throws Exception {
-        Map<String,Object> styles = new HashMap<>();
-        styles.put("color","#FF0000");
-        styles.put("color:active","#008000");
-        styles.put("fontSize:active:some_clz",20);
-        styles.put("color:active:enabled",15);
-        styles.put("color:active:disabled","#008000");
-        styles.put("fontSize:active:disabled",30);
-
-        WXStyle style = new WXStyle();
-        style.putAll(styles,false);
-
-        assertEquals(style.getPesudoStyles().get(":active").keySet().size(),1);
-        assertEquals(style.getPesudoStyles().get(":active:some_clz").get("fontSize"),20);
-        assertEquals(style.getPesudoStyles().get(":active:disabled").get("fontSize"),30);
-        assertEquals(style.getPesudoStyles().get(":active:disabled").keySet().size(),2);
-    }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/dom/WXTextDomObjectTest.java b/android/sdk/src/test/java/com/taobao/weex/dom/WXTextDomObjectTest.java
deleted file mode 100644
index c01259a..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/dom/WXTextDomObjectTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.dom;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-
-import static com.taobao.weex.common.Constants.Name.*;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.api.mockito.PowerMockito;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 26/09/2016.
- */
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-public class WXTextDomObjectTest {
-
-  WXTextDomObject dom;
-
-  @Before
-  public void setUp() throws Exception {
-    dom = new WXTextDomObject();
-    WXStyle styles = dom.getStyles();
-    styles.put(LINES,10);
-    styles.put(FONT_SIZE,10);
-
-    dom.getAttrs().put(VALUE,"test");
-  }
-
-  @Test
-  public void testLayoutBefore() throws Exception {
-    dom.layoutBefore();
-  }
-
-  @Test
-  public void testMeasure() throws Exception {
-    testLayoutBefore();
-    MeasureOutput output = new MeasureOutput();
-    WXTextDomObject mock = PowerMockito.spy(dom);
-    PowerMockito.when(mock,"getTextWidth",dom.getTextPaint(),100f,false).thenReturn(10f);
-    WXTextDomObject.TEXT_MEASURE_FUNCTION.measure(mock,100,output);
-
-    assertEquals(output.width,10f,0.1f);
-  }
-
-  @Test
-  public void testLayoutAfter() throws Exception {
-    dom.layoutAfter();
-  }
-
-  @Test
-  public void testClone() throws Exception {
-    WXTextDomObject cloneDom = dom.clone();
-
-    assertFalse(cloneDom == dom);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/http/WXStreamModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/http/WXStreamModuleTest.java
deleted file mode 100644
index e0a2aa3..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/http/WXStreamModuleTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.http;
-
-import android.os.Looper;
-import android.telecom.Call;
-
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.adapter.DefaultWXHttpAdapter;
-import com.taobao.weex.adapter.IWXHttpAdapter;
-import com.taobao.weex.bridge.JSCallback;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.common.WXResponse;
-import com.taobao.weex.common.WXThread;
-import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.util.*;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static org.mockito.Mockito.*;
-import static junit.framework.Assert.*;
-
-
-/**
- * Created by sospartan on 5/24/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@PrepareForTest({WXStreamModule.class, IWXHttpAdapter.class})
-@Config(manifest= Config.NONE)
-public class WXStreamModuleTest {
-
-  @Before
-  public void setup() throws Exception{
-
-  }
-
-  private WXResponse successResponse(){
-    WXResponse resp = new WXResponse();
-    resp.data = "data";
-    resp.statusCode = "200";
-    return resp;
-  }
-
-  static class Callback implements JSCallback{
-     Map<String, Object> mData;
-
-    @Override
-    public void invoke(Object data) {
-      mData = (Map<String,Object>)data;
-    }
-
-    @Override
-    public void invokeAndKeepAlive(Object data) {
-      mData = (Map<String,Object>)data;
-    }
-  }
-
-
-  @Test
-  public void testFetchInvaildOptions() throws Exception{
-    IWXHttpAdapter adapter = new IWXHttpAdapter() {
-      @Override
-      public void sendRequest(WXRequest request, OnHttpListener listener) {
-        listener.onHttpFinish(successResponse());
-      }
-    };
-
-    WXStreamModule streamModule = new WXStreamModule(adapter);
-    Callback cb = new Callback();
-    streamModule.fetch("",cb,null);
-
-    assert   !(boolean)cb.mData.get("ok");
-  }
-
-  private WXStreamModule createModule(IWXHttpAdapter adapter){
-    WXStreamModule m = new WXStreamModule(adapter);
-    m.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-    return m;
-  }
-
-  @Test
-  public void testFetchSuccessFinish() throws Exception{
-    IWXHttpAdapter adapter = new IWXHttpAdapter() {
-      @Override
-      public void sendRequest(WXRequest request, OnHttpListener listener) {
-        listener.onHttpFinish(successResponse());
-      }
-    };
-
-    WXStreamModule streamModule = createModule(adapter);
-    Callback cb = new Callback();
-    streamModule.fetch("{'url':'http://www.taobao.com'}",cb,null);
-
-    assert   (boolean)cb.mData.get("ok");
-  }
-
-
-  @Test
-  public void testFetchHeaderReceived() throws Exception{
-    IWXHttpAdapter adapter = new IWXHttpAdapter() {
-      @Override
-      public void sendRequest(WXRequest request, OnHttpListener listener) {
-        Map<String,List<String>> headers = new HashMap<>();
-        headers.put("key", Arrays.asList("someval"));
-        listener.onHeadersReceived(200,headers);
-      }
-    };
-
-    WXStreamModule streamModule = createModule(adapter);
-    Callback cb = new Callback();
-    streamModule.fetch("{'url':'http://www.taobao.com'}",null,cb);
-
-    assert   ((Map<String,String>)cb.mData.get("headers")).get("key").equals("someval");
-  }
-
-  @Test
-  public void testFetchRequestHttpbinCallback() throws Exception{
-    WXStreamModule streamModule = createModule(new DefaultWXHttpAdapter());
-    JSCallback progress = mock(JSCallback.class);
-    JSCallback finish = mock(JSCallback.class);
-    System.out.print("request start "+System.currentTimeMillis());
-    streamModule.fetch("{method: 'POST',url: 'http://httpbin.org/post',type:'json'}",finish,progress);
-    verify(progress,timeout(10*1000).atLeastOnce()).invokeAndKeepAlive(anyMapOf(String.class, Object.class));
-    verify(finish,timeout(10*1000).times(1)).invoke(anyMapOf(String.class, Object.class));
-    System.out.print("\nrequest finish"+System.currentTimeMillis());
-  }
-
-
-  @Test
-  public void testFetchStatus() throws Exception{
-    WXStreamModule streamModule = createModule(new IWXHttpAdapter() {
-      @Override
-      public void sendRequest(WXRequest request, OnHttpListener listener) {
-        WXResponse response = new WXResponse();
-        response.statusCode = "-1";
-        listener.onHttpFinish(response);
-      }
-    });
-    Callback finish = new Callback();
-
-    streamModule.fetch("",finish,null);
-    assertEquals(finish.mData.get(WXStreamModule.STATUS_TEXT),Status.ERR_INVALID_REQUEST);
-
-    streamModule.fetch("{method: 'POST',url: 'http://httpbin.org/post',type:'json'}",finish,null);
-    assertEquals(finish.mData.get(WXStreamModule.STATUS_TEXT),Status.ERR_CONNECT_FAILED);
-
-    streamModule = createModule(new IWXHttpAdapter() {
-      @Override
-      public void sendRequest(WXRequest request, OnHttpListener listener) {
-        WXResponse response = new WXResponse();
-        response.statusCode = "302";
-        listener.onHttpFinish(response);
-      }
-    });
-    streamModule.fetch("{method: 'POST',url: 'http://httpbin.org/post',type:'json'}",finish,null);
-    assertEquals(finish.mData.get(WXStreamModule.STATUS),302);
-    assertEquals(finish.mData.get(WXStreamModule.STATUS).getClass(),Integer.class);
-    assertEquals(finish.mData.get(WXStreamModule.STATUS_TEXT),Status.getStatusText("302"));
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/ComponentHolderTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/ComponentHolderTest.java
deleted file mode 100644
index 1ddb122..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/ComponentHolderTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.bridge.Invoker;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXVContainer;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Created by sospartan on 8/4/16.
- */
-public class ComponentHolderTest {
-    public static class TestComponentHolder implements IFComponentHolder{
-
-      WXComponent mComponent;
-      TestComponentHolder(WXComponent comp){
-        mComponent = comp;
-      }
-
-      @Override
-      public void loadIfNonLazy() {
-
-      }
-
-      @Override
-      public Invoker getPropertyInvoker(String name) {
-        return null;
-      }
-
-      @Override
-      public Invoker getMethodInvoker(String name) {
-        return null;
-      }
-
-      @Override
-      public String[] getMethods() {
-        return new String[0];
-      }
-
-      @Override
-      public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) throws IllegalAccessException, InvocationTargetException, InstantiationException {
-        mComponent.bindHolder(this);
-        return mComponent;
-      }
-    }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/WXRenderStatementTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/WXRenderStatementTest.java
deleted file mode 100644
index 1c4fef9..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/WXRenderStatementTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui;
-
-import android.text.TextUtils;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.ui.component.WXComponentFactory;
-import com.taobao.weex.utils.WXSoInstallMgrSdk;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by lixinke on 16/3/2.
- */
-@RunWith(PowerMockRunner.class)
-@Config(constants = BuildConfig.class)
-@PrepareForTest({WXSoInstallMgrSdk.class, TextUtils.class,WXComponentFactory.class})
-public class WXRenderStatementTest {
-
-    RenderContextImpl mWXRenderStatement;
-
-    @Before
-    public void setUp() throws Exception {
-        PowerMockito.mockStatic(WXSoInstallMgrSdk.class);
-        PowerMockito.mockStatic(TextUtils.class);
-        PowerMockito.mockStatic(WXComponentFactory.class);
-        PowerMockito.when(TextUtils.isEmpty("124")).thenReturn(true);
-        PowerMockito.when(WXSoInstallMgrSdk.initSo(null, 1, null)).thenReturn(true);
-        WXSDKInstance instance = Mockito.mock(WXSDKInstance.class);
-        mWXRenderStatement = new RenderContextImpl(instance);
-    }
-
-    public void testCreateBody() throws Exception {
-
-    }
-
-    @Test
-    public void testCreateBodyOnDomThread() throws Exception {
-
-    }
-
-    public void testSetPadding() throws Exception {
-
-    }
-
-    public void testSetLayout() throws Exception {
-
-    }
-
-    public void testSetExtra() throws Exception {
-
-    }
-
-    public void testAddComponent() throws Exception {
-
-    }
-
-    @Test
-    public void testCreateComponentOnDomThread() throws Exception {
-
-
-//        PowerMockito.mockStatic(TextUtils.class);
-//        PowerMockito.mockStatic(WXComponentFactory.class);
-//        PowerMockito.when(TextUtils.isEmpty("1234")).thenReturn(true);
-//        PowerMockito.when(WXComponentFactory.newInstance(null, null, null, null)).thenReturn(PowerMockito.mock(WXDiv.class));
-//
-//        WXDomObject object = PowerMockito.mock(WXDomObject.class);
-//        WXComponent wxComponent = mWXRenderStatement.createBodyOnDomThread(object);
-//        assertNotNull(wxComponent);
-
-    }
-
-    public void testAddComponent1() throws Exception {
-
-    }
-
-    public void testRemoveComponent() throws Exception {
-
-    }
-
-    public void testMove() throws Exception {
-
-    }
-
-    public void testAddEvent() throws Exception {
-
-    }
-
-    public void testRemoveEvent() throws Exception {
-
-    }
-
-    public void testUpdateAttrs() throws Exception {
-
-    }
-
-    public void testUpdateStyle() throws Exception {
-
-    }
-
-    public void testScrollTo() throws Exception {
-
-    }
-
-    public void testCreateFinish() throws Exception {
-
-    }
-
-    public void testRefreshFinish() throws Exception {
-
-    }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/animation/WXAnimationModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/animation/WXAnimationModuleTest.java
deleted file mode 100644
index 7dd4858..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/animation/WXAnimationModuleTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.animation;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 7/29/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*","org.json.*" })
-@PrepareForTest()
-public class WXAnimationModuleTest {
-
-
-  WXAnimationModule module;
-  @Before
-  public void setUp() throws Exception {
-    module = new WXAnimationModule();
-    module.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-
-
-  }
-
-  @Test
-  public void testTransition() throws Exception {
-    module.transition("","","");
-    module.transition("test","test","");
-  }
-
-  @Test
-  public void testCreateAnimatorListener() throws Exception {
-
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/ComponentTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/ComponentTest.java
deleted file mode 100644
index bcafc2a..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/ComponentTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.view.View;
-
-import com.taobao.weex.WXSDKInstance;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by sospartan on 8/3/16.
- */
-public class ComponentTest {
-  public static void create(WXComponent comp){
-    create(comp,null);
-  }
-  public static void create(WXComponent comp,View view){
-    TestDomObject domObject = new TestDomObject();
-    WXVContainer parent;
-
-    if((parent = comp.getParent())!=null){
-      if(view != null) {
-        comp.mHost = view;
-      }else{
-        comp.createView();
-      }
-    }else{
-      parent = WXDivTest.create();
-      parent.addChild(comp);
-      parent.createChildViewAt(-1);
-    }
-
-    comp.setSafeLayout(comp);
-
-//    domObject = new TestDomObject();
-//    comp.updateDom(domObject);
-    comp.applyLayoutAndEvent(comp);
-
-    addEvent(comp);
-  }
-
-
-  public static void setProperty(WXComponent comp,String[] propNames,Object[][] valueGroups){
-    Map<String, Object> props = new HashMap<>();
-    int len = propNames.length;
-
-    if(propNames.length != valueGroups.length){
-      throw new RuntimeException("Property name and value group length not match");
-    }
-    for (int i=0;i<len;i++){
-      for (Object obj:valueGroups[i]){
-        props.put(propNames[i],obj);
-        comp.updateProperties(props);
-      }
-
-    }
-  }
-
-  public static void addEvent(WXComponent comp){
-    for (String event :
-        TestConstants.Events) {
-      comp.addEvent(event);
-    }
-  }
-
-  public static void destory(WXComponent comp){
-    comp.destroy();
-  }
-
-  public static <T> T createComponent(WXDomObject dom, WXVContainer parent, Class<T> type) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
-     return type
-         .getConstructor(WXSDKInstance.class,WXDomObject.class,WXVContainer.class)
-        .newInstance(parent.getInstance(),dom,parent);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/EditComponentTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/EditComponentTest.java
deleted file mode 100644
index 8a40791..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/EditComponentTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import com.taobao.weex.ui.view.WXEditText;
-
-import junit.framework.Assert;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-
-import static com.taobao.weex.common.Constants.Name.*;
-import static com.taobao.weex.common.Constants.Value.*;
-
-/**
- * Created by sospartan on 8/3/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-@PrepareForTest
-public class EditComponentTest {
-  static final String[] PROPS = {
-      TEXT_ALIGN,
-      FONT_SIZE,
-      COLOR,
-      TYPE,
-      VALUE,
-      PLACE_HOLDER,
-      PLACEHOLDER_COLOR,
-      AUTOFOCUS,
-      LINES,
-      SINGLELINE,
-      MAX_LENGTH,
-      ROWS};
-  static final Object[][] TEST_VALUES = {
-      {null,CENTER, Constants.Name.LEFT, Constants.Name.RIGHT,"kdkdkdk"},
-      {null,12,Integer.MAX_VALUE,0,-2},
-      {"red","#000","#ffffff","rgb(12,23,45)"},
-      {"DKDK",
-          TEXT,
-          PASSWORD,
-          TEL,
-          EMAIL,
-          URL,
-          DATE,
-          TIME,
-          DATETIME},
-      {null,123,"dkdkdkdk"},
-      {null,123,"dkdkdkdk"},
-      {"red","#000","#ffffff","rgb(12,23,45)"},
-      {null,true,"true","false",false,"test"},
-      {null,34,Integer.MAX_VALUE,-1,"test"},
-      {null,true,"true","false",false,"test"},
-      {null,34,Integer.MAX_VALUE,-1,"test"},
-      {null,34,Integer.MAX_VALUE,-1,"test"},
-      };
-
-  AbstractEditComponent component;
-
-  public static WXInput create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXInput) new SimpleComponentHolder(WXInput.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  public static Textarea createTextarea() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (Textarea) new SimpleComponentHolder(Textarea.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    ComponentTest.create(component);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    ComponentTest.destory(component);
-  }
-
-  @Test
-  public void testEvent() throws Exception {
-    WXEditText view = component.getHostView();
-    view.performClick();
-    view.setText("");
-    view.requestFocus();
-    view.setText("hello");
-    view.clearFocus();
-    view.setText(null);
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-
-    ComponentTest.setProperty(component,PROPS,TEST_VALUES);
-  }
-
-  @Test
-  public void testFocus() throws Exception {
-    component.getParent().mHost = component.getParent().initComponentHostView(component.getContext());
-    component.getParent().interceptFocus();
-    component.getHostView().clearFocus();
-    component.focus();
-    Assert.assertEquals(component.getHostView().hasFocus(), true);
-  }
-
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/TestComponent.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/TestComponent.java
deleted file mode 100644
index 1ac43e6..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/TestComponent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weex.WXSDKInstance;
-
-/**
- * Created by sospartan on 7/27/16.
- */
-public class TestComponent extends WXDiv{
-  public TestComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) {
-    super(instance, dom, parent, instanceId, isLazy);
-  }
-
-  public TestComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent) {
-    super(instance, dom, parent);
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/TestConstants.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/TestConstants.java
deleted file mode 100644
index f0d060b..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/TestConstants.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weex.common.Constants;
-
-/**
- * Created by sospartan on 8/9/16.
- */
-public class TestConstants {
-  public static final String Events[] = {"", null,
-      Constants.Event.INPUT,
-      Constants.Event.APPEAR,
-      Constants.Event.BLUR,
-      Constants.Event.CLICK,
-      Constants.Event.CHANGE,
-      Constants.Event.FOCUS,
-      Constants.Event.DISAPPEAR,
-  };
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/TextareaTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/TextareaTest.java
deleted file mode 100644
index 33fe97d..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/TextareaTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 8/9/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class TextareaTest  {
-
-  Textarea component;
-
-  @Before
-  public void setUp() throws Exception {
-    component = EditComponentTest.createTextarea();
-    ComponentTest.create(component);
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-    Map<String, Object> props = new HashMap<>();
-    int len = EditComponentTest.PROPS.length;
-
-    for (int i = 0; i < len; i++) {
-      for (Object obj : EditComponentTest.TEST_VALUES[i]) {
-        props.put(EditComponentTest.PROPS[i], obj);
-        component.updateProperties(props);
-      }
-
-    }
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    ComponentTest.destory(component);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXComponentTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXComponentTest.java
deleted file mode 100644
index 8ea91f1..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXComponentTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.common.Constants;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 7/27/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXComponentTest {
-
-  WXComponent component;
-
-  @Before
-  public void setUp() throws Exception {
-    WXVContainer root = WXDivTest.create();
-    ComponentTest.create(root);
-    component = WXDivTest.create(root);
-    ComponentTest.create(component);
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-
-    assertTrue(component.setProperty(Constants.Name.VISIBILITY,null));
-    assertTrue(component.setProperty(Constants.Name.VISIBILITY, Constants.Value.VISIBLE));
-
-    assertTrue(component.setProperty(Constants.Name.DISABLED,true));
-    assertTrue(component.setProperty(Constants.Name.POSITION, Constants.Value.FIXED));
-    assertTrue(component.setProperty(Constants.Name.BACKGROUND_COLOR, "#ffffff"));
-    assertTrue(component.setProperty(Constants.Name.OPACITY, 0.5f));
-    assertTrue(component.setProperty(Constants.Name.BORDER_RADIUS,0.5f));
-    assertTrue(component.setProperty(Constants.Name.BORDER_RADIUS,null));
-    assertTrue(component.setProperty(Constants.Name.BORDER_WIDTH,null));
-    assertTrue(component.setProperty(Constants.Name.BORDER_WIDTH,10));
-    assertTrue(component.setProperty(Constants.Name.BORDER_STYLE,null));
-    assertTrue(component.setProperty(Constants.Name.BORDER_STYLE, "SOLID"));
-    assertTrue(component.setProperty(Constants.Name.BORDER_COLOR,null));
-    assertTrue(component.setProperty(Constants.Name.BORDER_COLOR, "#ff0000"));
-
-    assertTrue(component.setProperty(Constants.Name.BORDER_TOP_LEFT_RADIUS, 1));
-    assertTrue(component.setProperty(Constants.Name.BORDER_TOP_RIGHT_RADIUS, 1));
-    assertTrue(component.setProperty(Constants.Name.BORDER_BOTTOM_LEFT_RADIUS, 1));
-    assertTrue(component.setProperty(Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS, 1));
-    assertTrue(component.setProperty(Constants.Name.BORDER_TOP_WIDTH, 1));
-    assertTrue(component.setProperty(Constants.Name.BORDER_LEFT_WIDTH, 1));
-    assertTrue(component.setProperty(Constants.Name.BORDER_BOTTOM_WIDTH, 1));
-    assertTrue(component.setProperty(Constants.Name.BORDER_RIGHT_WIDTH,1));
-
-    assertTrue(component.setProperty(Constants.Name.BORDER_TOP_COLOR, "#ff0000"));
-    assertTrue(component.setProperty(Constants.Name.BORDER_BOTTOM_COLOR, "#ff0000"));
-    assertTrue(component.setProperty(Constants.Name.BORDER_LEFT_COLOR, "#ff0000"));
-    assertTrue(component.setProperty(Constants.Name.BORDER_RIGHT_COLOR, "#ff0000"));
-
-    assertTrue(component.setProperty(Constants.Name.WIDTH, null));
-    assertTrue(component.setProperty(Constants.Name.MIN_WIDTH, null));
-    assertTrue(component.setProperty(Constants.Name.MAX_WIDTH, null));
-    assertTrue(component.setProperty(Constants.Name.HEIGHT, null));
-    assertTrue(component.setProperty(Constants.Name.MIN_HEIGHT, null));
-    assertTrue(component.setProperty(Constants.Name.MAX_HEIGHT, null));
-    assertTrue(component.setProperty(Constants.Name.ALIGN_ITEMS, null));
-    assertTrue(component.setProperty(Constants.Name.ALIGN_SELF, null));
-    assertTrue(component.setProperty(Constants.Name.FLEX, null));
-    assertTrue(component.setProperty(Constants.Name.FLEX_DIRECTION, null));
-    assertTrue(component.setProperty(Constants.Name.JUSTIFY_CONTENT, null));
-    assertTrue(component.setProperty(Constants.Name.FLEX_WRAP, null));
-    assertTrue(component.setProperty(Constants.Name.MARGIN, null));
-    assertTrue(component.setProperty(Constants.Name.MARGIN_TOP, null));
-    assertTrue(component.setProperty(Constants.Name.MARGIN_LEFT, null));
-    assertTrue(component.setProperty(Constants.Name.MARGIN_RIGHT, null));
-    assertTrue(component.setProperty(Constants.Name.MARGIN_BOTTOM, null));
-    assertTrue(component.setProperty(Constants.Name.PADDING, null));
-    assertTrue(component.setProperty(Constants.Name.PADDING_TOP, null));
-    assertTrue(component.setProperty(Constants.Name.PADDING_LEFT, null));
-    assertTrue(component.setProperty(Constants.Name.PADDING_RIGHT, null));
-    assertTrue(component.setProperty(Constants.Name.PADDING_BOTTOM, null));
-
-  }
-
-
-  @Test
-  public void testAddEvent() throws Exception {
-    component.addEvent(Constants.Event.FOCUS);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java
deleted file mode 100644
index 310af8e..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.dom.WXEvent;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by gulin on 16/2/24.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-public class WXDivTest {
-
-    private WXDiv mWXDiv;
-    private WXText child2;
-
-
-    public static WXDiv create(){
-        return create(null);
-    }
-
-    public static WXDiv create(WXVContainer parent){
-        WXDiv div = new WXDiv(WXSDKInstanceTest.createInstance(),new TestDomObject(),parent);
-        return div;
-    }
-
-
-    @Before
-    public void setUp() throws Exception {
-        WXSDKInstance instance = Mockito.mock(WXSDKInstance.class);
-        Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application);
-
-        WXDomObject divDom = new WXDomObject();
-        WXDomObject spy = Mockito.spy(divDom);
-        Mockito.when(spy.getPadding()).thenReturn(new Spacing());
-        Mockito.when(spy.getEvents()).thenReturn(new WXEvent());
-        Mockito.when(spy.clone()).thenReturn(divDom);
-        TestDomObject.setRef(divDom,"1");
-        mWXDiv = new WXDiv(instance, divDom, null);
-        mWXDiv.initView();
-    }
-
-    @Test
-    public void testAddChild(){
-        WXSDKInstance instance = Mockito.mock(WXSDKInstance.class);
-        Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application);
-
-        WXDomObject testDom = Mockito.mock(WXDomObject.class);
-        Mockito.when(testDom.getPadding()).thenReturn(new Spacing());
-        Mockito.when(testDom.clone()).thenReturn(testDom);
-        TestDomObject.setRef(testDom,"2");
-        WXText child1 = new WXText(instance, testDom, mWXDiv);
-        child1.initView();
-
-        mWXDiv.addChild(child1, 0);
-
-        assertEquals(1, mWXDiv.childCount());
-
-        WXDomObject testDom2 = Mockito.spy(new WXDomObject());
-        Mockito.when(testDom2.getPadding()).thenReturn(new Spacing());
-        Mockito.when(testDom2.clone()).thenReturn(testDom2);
-        TestDomObject.setRef(testDom2,"3");
-        child2 = new WXText(instance, testDom2, mWXDiv);
-        child2.initView();
-
-        mWXDiv.addChild(child2, -1);
-
-        assertEquals(2, mWXDiv.childCount());
-        assertEquals(child2, mWXDiv.getChild(1));
-
-        WXDomObject testDom3 = Mockito.mock(WXDomObject.class);
-        Mockito.when(testDom3.getPadding()).thenReturn(new Spacing());
-        Mockito.when(testDom3.clone()).thenReturn(testDom3);
-        TestDomObject.setRef(testDom3,"4");
-        WXText child3 = new WXText(instance, testDom3, mWXDiv);
-        child3.initView();
-
-        mWXDiv.addChild(child3, 1);
-
-        assertEquals(3, mWXDiv.childCount());
-        assertEquals(child3, mWXDiv.getChild(1));
-    }
-
-    @Test
-    public void testRemove(){
-        testAddChild();
-        mWXDiv.remove(child2,true);
-
-        assertEquals(2, mWXDiv.childCount());
-    }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXEmbedTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXEmbedTest.java
deleted file mode 100644
index 752b425..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXEmbedTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.common.Constants;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 26/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-public class WXEmbedTest {
-
-  WXEmbed component;
-
-  @Before
-  public void setUp() throws Exception {
-
-    WXEnvironment.sApplication = RuntimeEnvironment.application;
-    WXDiv div = WXDivTest.create();
-    ComponentTest.create(div);
-    component = new WXEmbed(div.getInstance(),new TestDomObject(),div);
-    ComponentTest.create(component);
-    component.getDomObject().getStyles().put(Constants.Name.VISIBILITY, Constants.Value.VISIBLE);
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-    component.setProperty(Constants.Name.SRC,"http://www.taobao.com");
-  }
-
-  @Test
-  public void testSetVisibility() throws Exception {
-    component.setProperty(Constants.Name.VISIBILITY,Constants.Value.HIDDEN);
-    component.setProperty(Constants.Name.SRC,"http://www.taobao.com");
-    component.setProperty(Constants.Name.VISIBILITY,Constants.Value.VISIBLE);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXHeaderTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXHeaderTest.java
deleted file mode 100644
index 740f7c4..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXHeaderTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.ui.SimpleComponentHolder;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Created by sospartan on 8/29/16.
- */
-public class WXHeaderTest {
-
-  public static WXHeader create(WXVContainer parent) throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXHeader) new SimpleComponentHolder(WXHeader.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), parent);
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXImageTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXImageTest.java
deleted file mode 100644
index 9999f71..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXImageTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.TestActivity;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.common.WXImageSharpen;
-import com.taobao.weex.dom.WXAttr;
-import com.taobao.weex.ui.view.WXImageView;
-import com.taobao.weex.ui.view.border.BorderDrawable;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXImageTest {
-
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-
-  WXImage mWXImage;
-  WXSDKInstance mInstance;
-  WXDiv mWXDiv;
-  WXDomObject mDomObject;
-
-  @Before
-  public void setUp() throws Exception {
-
-    mInstance = WXSDKInstanceTest.createInstance();
-    mDomObject = new TestDomObject();
-    PowerMockito.when(Mockito.spy(mDomObject).clone()).thenReturn(mDomObject);
-    mWXDiv = PowerMockito.mock(WXDiv.class);
-    mWXImage = new WXImage(mInstance, mDomObject, mWXDiv);
-
-  }
-
-
-  @Test
-  @PrepareForTest(WXImageView.class)
-  public void testInitComponentHostView() throws Exception {
-
-    ImageView imageView = mWXImage.initComponentHostView(Robolectric.setupActivity(TestActivity.class));
-    assertEquals(imageView.getClass(), WXImageView.class);
-
-  }
-
-  @Test
-  @PrepareForTest(WXImageView.class)
-  public void testSetBackgroundColor() throws Exception {
-
-    ImageView imageView = mWXImage.initComponentHostView(Robolectric.setupActivity(TestActivity.class));
-    mWXImage.mHost = imageView;
-
-    mWXImage.setBackgroundColor("#FFFFFF");
-
-    Drawable drawable = mWXImage.getHostView().getBackground();
-    assertEquals(drawable instanceof BorderDrawable, true);
-  }
-
-
-  @Test
-  public void testSetProperty() throws Exception {
-
-    ImageView imageView = mWXImage.initComponentHostView(Robolectric.setupActivity(TestActivity.class));
-    mWXImage.mHost = imageView;
-
-    mWXImage.setProperty(Constants.Name.RESIZE_MODE, "cover");
-    ImageView.ScaleType scaleType = mWXImage.getHostView().getScaleType();
-    assertEquals(scaleType, ImageView.ScaleType.CENTER_CROP);
-
-
-  }
-
-
-  @Test
-  public void testSetResizeMode() throws Exception {
-
-    ImageView imageView = mWXImage.initComponentHostView(Robolectric.setupActivity(TestActivity.class));
-    mWXImage.mHost = imageView;
-
-    mWXImage.setResizeMode("cover");
-    ImageView.ScaleType scaleType = mWXImage.getHostView().getScaleType();
-    assertEquals(scaleType, ImageView.ScaleType.CENTER_CROP);
-
-  }
-
-  @Test
-  public void testSetResize() throws Exception {
-    ImageView imageView = mWXImage.initComponentHostView(Robolectric.setupActivity(TestActivity.class));
-    mWXImage.mHost = imageView;
-
-    mWXImage.setResize("cover");
-    ImageView.ScaleType scaleType = mWXImage.getHostView().getScaleType();
-    assertEquals(scaleType, ImageView.ScaleType.CENTER_CROP);
-  }
-
-  @Test
-  public void testSetSrc() throws Exception {
-    TestDomObject.setAttribute((WXDomObject)mWXImage.getDomObject(),PowerMockito.mock(WXAttr.class));
-    PowerMockito.when(mWXImage.getDomObject().getAttrs().getImageSharpen()).thenReturn(WXImageSharpen.SHARPEN);
-    mWXImage.setSrc("");
-
-  }
-
-  @Test
-  public void testSetImageBitmap(){
-    ImageView imageView = mWXImage.initComponentHostView(Robolectric.setupActivity(TestActivity.class));
-    imageView.setLayoutParams(new ViewGroup.LayoutParams(
-        ViewGroup.LayoutParams.WRAP_CONTENT,
-        ViewGroup.LayoutParams.WRAP_CONTENT));
-    imageView.setImageBitmap(null);
-    assertNull(imageView.getDrawable());
-
-    imageView.setImageBitmap(Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565));
-    assertNotNull(imageView.getDrawable());
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXLoadingTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXLoadingTest.java
deleted file mode 100644
index 59d803e..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXLoadingTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Created by sospartan on 28/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXLoadingTest {
-
-  public static WXLoading create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXLoading) new SimpleComponentHolder(WXLoading.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  WXLoading component;
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    ComponentTest.create(component);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-
-  @Test
-  public void testOnLoading() throws Exception {
-    component.onLoading();
-  }
-
-
-  @Test
-  public void testSetProperty() throws Exception {
-    component.setProperty(Constants.Name.DISPLAY,WXLoading.HIDE);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXRefreshTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXRefreshTest.java
deleted file mode 100644
index 99ca151..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXRefreshTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Created by sospartan on 28/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXRefreshTest {
-
-  public static WXRefresh create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXRefresh) new SimpleComponentHolder(WXRefresh.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  WXRefresh component;
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    ComponentTest.create(component);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-
-  @Test
-  public void testOnRefresh() throws Exception {
-    component.onRefresh();
-  }
-
-  @Test
-  public void testOnPullingDown() throws Exception {
-    component.onPullingDown(10,100,100);
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-    component.setProperty(Constants.Name.DISPLAY,WXRefresh.HIDE);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXScrollerTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXScrollerTest.java
deleted file mode 100644
index 185ab2e..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXScrollerTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.ui.view.WXScrollView;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 8/25/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXScrollerTest {
-
-  public static WXScroller create(){
-    WXDiv div = WXDivTest.create();
-    ComponentTest.create(div);
-    WXScroller component = new WXScroller(WXSDKInstanceTest.createInstance(),new WXScrollerDomObject(),div);
-    div.addChild(component);
-    return component;
-  }
-
-
-  WXScroller component;
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    ComponentTest.create(component);
-  }
-
-  @Test
-  public void testAddChild() throws Exception{
-    WXDiv div = WXDivTest.create(component);
-    component.addChild(div);
-    ComponentTest.create(div);
-
-  }
-
-  @Test
-  public void testScroll() throws Exception {
-    WXScroller comp = create();
-    WXDiv div = WXDivTest.create(comp);
-    ComponentTest.create(div);
-    comp.addChild(div);
-    ComponentTest.create(comp);
-    WXScrollView view = (WXScrollView) comp.getInnerView();
-    view.scrollTo(100,100);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSliderNeighborTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSliderNeighborTest.java
deleted file mode 100644
index 0f18fa5..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSliderNeighborTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 27/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXSliderNeighborTest {
-
-  public static WXSliderNeighbor create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXSliderNeighbor) new SimpleComponentHolder(WXSliderNeighbor.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  WXSliderNeighbor component;
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    ComponentTest.create(component);
-  }
-
-  @Test
-  public void testPages() throws Exception {
-    component = create();
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-
-    WXIndicator indicator = new WXIndicator(component.getInstance(),new TestDomObject(),component,false);
-    ComponentTest.create(indicator);
-    component.addChild(indicator);
-    ComponentTest.create(component);
-
-    assertEquals(5,component.mViewPager.getCirclePageAdapter().getRealCount());
-    assertEquals(6,component.getChildCount());
-
-    component.mViewPager.setCurrentItem(0);
-  }
-
-  @Test
-  public void testSetProperties() throws Exception {
-    component.setProperty(WXSliderNeighbor.NEIGHBOR_ALPHA,0.4f);
-    component.setProperty(WXSliderNeighbor.NEIGHBOR_SCALE,0.9f);
-  }
-
-  @Test
-  public void testZoomTransformer() throws Exception {
-    component = create();
-    TestComponent page = ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class);
-    TestComponent pageChild = ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class);
-    page.addChild(pageChild);
-    component.addChild(page);
-
-    ComponentTest.create(component);
-//    ComponentTest.create(pageChild);
-//    ComponentTest.create(page);
-    WXSliderNeighbor.ZoomTransformer transformer = component.createTransformer();
-    transformer.transformPage(page.getHostView(),0.2f);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSliderTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSliderTest.java
deleted file mode 100644
index 697d3b4..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSliderTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.ui.SimpleComponentHolder;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-
-import static com.taobao.weex.common.Constants.Name;
-import static org.junit.Assert.assertEquals;
-
-/**
- * Created by sospartan on 8/9/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXSliderTest {
-
-  WXSlider component;
-
-  static final String[] PROPS = {
-      Name.AUTO_PLAY,
-      Name.VALUE,
-      "unknown",
-      Name.INTERVAL,
-      Name.INDEX,
-      Name.SHOW_INDICATORS
-  };
-
-  static final Object[][] VALUES = {
-      {"","true","false",true,false,null},
-      {"","1","0",1,-1,null},
-      {null,"","test"},
-      {"","100","0",100,-1,null},
-      {"","1","0",1,2,3,-1,null},
-      {"","true","false",true,false,null}
-  };
-
-  public static WXSlider create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXSlider) new SimpleComponentHolder(WXSlider.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  public static WXIndicator createIndicator() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXIndicator) new SimpleComponentHolder(WXIndicator.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  public static WXIndicator createIndicator(WXVContainer container) throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXIndicator) new SimpleComponentHolder(WXIndicator.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), container);
-  }
-
-  @Before
-  public void setup() throws Exception {
-    component = create();
-    ComponentTest.create(component);
-  }
-
-  @Test
-  public void testSetProperties() throws Exception {
-    ComponentTest.setProperty(component,PROPS,VALUES);
-  }
-
-  @Test
-  public void testPages() throws Exception {
-    component = create();
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-    component.addChild(ComponentTest.createComponent(new TestDomObject(),component,TestComponent.class));
-
-    WXIndicator indicator = new WXIndicator(component.getInstance(),new TestDomObject(),component,false);
-    ComponentTest.create(indicator);
-    component.addChild(indicator);
-    ComponentTest.create(component);
-
-    assertEquals(5,component.mViewPager.getCirclePageAdapter().getRealCount());
-    assertEquals(6,component.getChildCount());
-
-    component.mViewPager.setCurrentItem(0);
-  }
-
-  static final String[] IPROPS = {
-      Name.ITEM_SIZE,
-      Name.ITEM_SELECTED_COLOR,
-      Name.ITEM_COLOR,
-      "unknown"
-  };
-
-  static final Object[][] IVALUES = {
-      {"0",0,1,"test"},
-      {"#ffffff",123,-1},
-      {"#ffffff",123,-1},
-      {"#ffffff",123,-1},
-  };
-
-  @Test
-  public void testIndicator() throws Exception {
-    WXIndicator indicator = createIndicator(component);
-    ComponentTest.create(indicator);
-    component.addChild(indicator);
-    ComponentTest.setProperty(indicator,IPROPS,IVALUES);
-  }
-
-  @Test
-  public void testOnScrollListener() throws Exception {
-    component.mViewPager.addOnPageChangeListener(new WXSlider.SliderOnScrollListener(component));
-    component.setOffsetXAccuracy(0.05f);
-    component.mViewPager.setCurrentItem(0);
-    for (int index=1;index<component.mViewPager.getRealCount();index++) {
-      component.mViewPager.setCurrentItem(index,true);
-    }
-    for (int index=component.mViewPager.getRealCount() - 1;index>=0;index--) {
-      component.mViewPager.setCurrentItem(index,true);
-    }
-    component.mViewPager.setCurrentItem(3,true);
-    component.mViewPager.setCurrentItem(0,true);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    ComponentTest.destory(component);
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSwitchTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSwitchTest.java
deleted file mode 100644
index 63f8d6a..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXSwitchTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import com.taobao.weex.ui.view.WXSwitchView;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Created by sospartan on 28/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXSwitchTest {
-
-  public static WXSwitch create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXSwitch) new SimpleComponentHolder(WXSwitch.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  WXSwitch component;
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    ComponentTest.create(component, Mockito.mock(WXSwitchView.class));
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-
-  @Test
-  public void testAddEvent() throws Exception {
-    component.addEvent(Constants.Event.CHANGE);
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-    component.setProperty(Constants.Name.CHECKED,true);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java
deleted file mode 100644
index c311ffb..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.SimpleComponentHolder;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Created by gulin on 16/2/4.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class)
-public class WXTextTest {
-    private WXText mWXText;
-    private WXDiv mParent;
-    private WXTextDomObject mDomObject;
-    private WXDomObject mParentDomObj;
-
-    @Before
-    public void setUp() throws Exception {
-        WXEnvironment.sApplication = RuntimeEnvironment.application;
-        WXSDKInstance instance = Mockito.mock(WXSDKInstance.class);
-        Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application);
-
-        mParentDomObj = Mockito.spy(new WXDomObject());
-        Mockito.when(mParentDomObj.getPadding()).thenReturn(new Spacing());
-        Mockito.when(mParentDomObj.getBorder()).thenReturn(new Spacing());
-        Mockito.when(mParentDomObj.clone()).thenReturn(mParentDomObj);
-        TestDomObject.setRef(mParentDomObj,WXDomObject.ROOT);
-
-        mDomObject = Mockito.spy(new WXTextDomObject());
-        TestDomObject.setRef(mDomObject,"1");
-        mDomObject.addEvent(Constants.Event.CLICK);
-        Mockito.when(mDomObject.clone()).thenReturn(mDomObject);
-        Mockito.when(mDomObject.getPadding()).thenReturn(new Spacing());
-        Mockito.when(mDomObject.getBorder()).thenReturn(new Spacing());
-        Mockito.when(mDomObject.getMargin()).thenReturn(new Spacing());
-        Mockito.when(mDomObject.getLayoutWidth()).thenReturn(100f);
-        Mockito.when(mDomObject.getLayoutHeight()).thenReturn(100f);
-
-        mParent = new WXDiv(instance, mParentDomObj, null);
-        mParent.createView();
-        mWXText = new WXText(instance, mDomObject, mParent);
-        mWXText.bindHolder(new SimpleComponentHolder(WXText.class));
-        assertNotNull(instance.getContext());
-    }
-
-    @Test
-    public void testSetProperties() throws Exception {
-        mWXText.setProperty(Constants.Name.LINES,null);
-        mWXText.setProperty(Constants.Name.FONT_SIZE,null);
-        mWXText.setProperty(Constants.Name.FONT_WEIGHT,null);
-        mWXText.setProperty(Constants.Name.FONT_STYLE,null);
-        mWXText.setProperty(Constants.Name.COLOR,null);
-        mWXText.setProperty(Constants.Name.TEXT_DECORATION,null);
-        mWXText.setProperty(Constants.Name.FONT_FAMILY,null);
-        mWXText.setProperty(Constants.Name.TEXT_ALIGN,null);
-        mWXText.setProperty(Constants.Name.TEXT_OVERFLOW,null);
-        mWXText.setProperty(Constants.Name.LINE_HEIGHT,null);
-    }
-
-    @Test
-    public void testCreateView(){
-        mWXText.createView();
-        assertNotNull(mWXText.getHostView());
-    }
-
-    @Test
-    public void testSetLayout(){
-        testCreateView();
-        mWXText.setLayout(mDomObject);
-        assertNotNull(mWXText.getHostView().getLayoutParams());
-        assertEquals(100, mWXText.getHostView().getLayoutParams().height);
-        assertEquals(100, mWXText.getHostView().getLayoutParams().width);
-    }
-
-    @Test
-    public void testSetPadding(){
-        testCreateView();
-        mWXText.setPadding(mDomObject.getPadding(), mDomObject.getBorder());
-        assertEquals(0, mWXText.getHostView().getPaddingLeft());
-        assertEquals(0, mWXText.getHostView().getPaddingTop());
-        assertEquals(0, mWXText.getHostView().getPaddingRight());
-        assertEquals(0, mWXText.getHostView().getPaddingBottom());
-    }
-
-    @Test
-    public void testBind(){
-        testCreateView();
-//        mWXText.bind(null);
-        mWXText.applyLayoutAndEvent(mWXText);
-        mWXText.bindData(mWXText);
-
-        assertNotNull(mWXText.getHostView().getLayoutParams());
-        assertEquals(100, mWXText.getHostView().getLayoutParams().height);
-        assertEquals(100, mWXText.getHostView().getLayoutParams().width);
-
-        assertEquals(0, mWXText.getHostView().getPaddingLeft());
-        assertEquals(0, mWXText.getHostView().getPaddingTop());
-        assertEquals(0, mWXText.getHostView().getPaddingRight());
-        assertEquals(0, mWXText.getHostView().getPaddingBottom());
-    }
-
-    @Test
-    public void testAddEvent(){
-        testBind();
-        mWXText.addEvent(Constants.Event.CLICK);
-        assertTrue(mWXText.getHostView().isEnabled());
-        mWXText.getHostView().performClick();
-    }
-
-    @Test
-    public void testUpdateProperties(){
-        testBind();
-        Map<String, Object> prop = new HashMap<>();
-        prop.put(Constants.Name.DISABLED, "false");
-        prop.put(Constants.Name.OPACITY, 0.8f);
-        mWXText.updateProperties(prop);
-        assertTrue(mWXText.getHostView().isEnabled());
-        assertEquals(0.8f, mWXText.getHostView().getAlpha(), 0.001f);
-
-        prop.put(Constants.Name.DISABLED, "true");
-        mWXText.updateProperties(prop);
-        assertFalse(mWXText.getHostView().isEnabled());
-    }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXVideoTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXVideoTest.java
deleted file mode 100644
index d01caa5..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXVideoTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * Created by sospartan on 8/10/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXVideoTest {
-
-  WXVideo component;
-
-  static final String[] PROPS = {
-      Constants.Name.PLAY_STATUS,
-      Constants.Name.AUTO_PLAY,
-      "unknown",
-      Constants.Name.SRC,
-  };
-
-  static final Object[][] VALUES = {
-      {"", Constants.Value.PLAY, Constants.Value.PAUSE,Constants.Value.STOP,null},
-      {"","true","false",true,false,null},
-      {null,"","test"},
-      {"","http://taobao.com","0",100,null},
-  };
-
-  public static WXVideo create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXVideo) new SimpleComponentHolder(WXVideo.class)
-        .createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    ComponentTest.create(component);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    ComponentTest.destory(component);
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-    component.mPrepared = true;
-    ComponentTest.setProperty(component,PROPS,VALUES);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXWebTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXWebTest.java
deleted file mode 100644
index 53d1773..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXWebTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component;
-
-import android.view.View;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.common.Constants;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import com.taobao.weex.ui.view.IWebView;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by sospartan on 28/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXWebTest {
-
-  public static WXWeb create() throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXWeb) new SimpleComponentHolder(WXWeb.class).createInstance(WXSDKInstanceTest.createInstance(), new TestDomObject(), WXDivTest.create());
-  }
-
-  WXWeb component;
-  ProxyWebView mWebView;
-
-  static class ProxyWebView implements IWebView {
-    IWebView mIWebView;
-    OnPageListener mOnPageListener;
-    OnErrorListener mOnErrorListener;
-    OnMessageListener mOnMessageListener;
-
-    ProxyWebView(IWebView proxy){
-      mIWebView = proxy;
-    }
-
-    @Override
-    public View getView() {
-      return mIWebView.getView();
-    }
-
-    @Override
-    public void destroy() {
-      mIWebView.destroy();
-    }
-
-    @Override
-    public void loadUrl(String url) {
-      mIWebView.loadUrl(url);
-    }
-
-    @Override
-    public void loadDataWithBaseURL(String source) {
-      mIWebView.loadDataWithBaseURL(source);
-    }
-
-    @Override
-    public void reload() {
-      mIWebView.reload();
-    }
-
-    @Override
-    public void goBack() {
-      mIWebView.goBack();
-    }
-
-    @Override
-    public void goForward() {
-      mIWebView.goForward();
-    }
-
-    @Override
-    public void postMessage(Object msg) {}
-
-    @Override
-    public void setShowLoading(boolean shown) {
-      mIWebView.setShowLoading(shown);
-    }
-
-    @Override
-    public void setOnErrorListener(OnErrorListener listener) {
-      mIWebView.setOnErrorListener(listener);
-      mOnErrorListener = listener;
-    }
-
-    @Override
-    public void setOnPageListener(OnPageListener listener) {
-      mIWebView.setOnPageListener(listener);
-      mOnPageListener = listener;
-    }
-
-    @Override
-    public void setOnMessageListener(OnMessageListener listener) {
-      mIWebView.setOnMessageListener(listener);
-      mOnMessageListener = listener;
-    }
-  }
-
-  @Before
-  public void setUp() throws Exception {
-    component = create();
-    mWebView = new ProxyWebView(component.mWebView);
-    component.mWebView = mWebView;
-    ComponentTest.create(component);
-
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-
-  @Test
-  public void testSetProperty() throws Exception {
-    component.setProperty(Constants.Name.SHOW_LOADING,true);
-    component.setProperty(Constants.Name.SRC,"http://taobao.com");
-    component.setProperty(Constants.Name.SOURCE, "<p><span>hello weex</span></p>");
-  }
-
-  @Test
-  public void testSetAction() throws Exception {
-    Map<String, Object> msg = new HashMap<>();
-    msg.put("test1", 1);
-    msg.put("test2", "2");
-    component.setAction(WXWeb.GO_BACK, null);
-    component.setAction(WXWeb.GO_FORWARD, null);
-    component.setAction(WXWeb.RELOAD, null);
-    component.setAction(WXWeb.POST_MESSAGE, msg);
-  }
-
-  @Test
-  public void testListener() throws Exception {
-    Map<String, Object> msg = new HashMap<>();
-    msg.put("test1", 1);
-    msg.put("test2", "2");
-    component.addEvent(Constants.Event.RECEIVEDTITLE);
-    component.addEvent(Constants.Event.PAGESTART);
-    component.addEvent(Constants.Event.PAGEFINISH);
-    component.addEvent(Constants.Event.ERROR);
-    component.addEvent(Constants.Event.ONMESSAGE);
-    mWebView.mOnPageListener.onPageFinish("http://taobao.com",true,true);
-    mWebView.mOnPageListener.onReceivedTitle("test");
-    mWebView.mOnPageListener.onPageStart("http://taobao.com");
-    mWebView.mOnErrorListener.onError("test","error occurred");
-    mWebView.mOnMessageListener.onMessage(msg);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/helper/WXTimeInputHelperTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/helper/WXTimeInputHelperTest.java
deleted file mode 100644
index f9e9ee2..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/helper/WXTimeInputHelperTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.helper;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.appfram.pickers.DatePickerImpl;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.Method;
-
-/**
- * Created by moxun on 16/10/24.
- */
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*", "org.json.*"})
-@PrepareForTest()
-public class WXTimeInputHelperTest {
-    @Rule
-    public PowerMockRule rule = new PowerMockRule();
-
-    @Test
-    public void testParseDate() throws Exception{
-        Method parseDate = DatePickerImpl.class.getDeclaredMethod("parseDate", String.class);
-        parseDate.setAccessible(true);
-        parseDate.invoke(null, "");
-        parseDate.invoke(null, "test");
-        parseDate.invoke(null, "2016-12-11");
-        parseDate.invoke(null, "2016-1-1");
-        parseDate.invoke(null, "9999-99-99");
-    }
-
-    @Test
-    public void testParseTime() throws Exception{
-        Method parseTime = DatePickerImpl.class.getDeclaredMethod("parseTime", String.class);
-        parseTime.setAccessible(true);
-        parseTime.invoke(null, "");
-        parseTime.invoke(null, "test");
-        parseTime.invoke(null, "11:11");
-        parseTime.invoke(null, "1:1");
-        parseTime.invoke(null, "25:61");
-    }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/list/DefaultDragHelperTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/list/DefaultDragHelperTest.java
deleted file mode 100644
index 474bdcf..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/list/DefaultDragHelperTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import com.taobao.weex.ui.component.ComponentTest;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXDiv;
-import com.taobao.weex.ui.component.WXDivTest;
-import com.taobao.weex.ui.component.WXVContainer;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyMap;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class DefaultDragHelperTest {
-
-    WXListComponent listComponent;
-
-    WXCell fakeCell;
-
-    private DragHelper mFakeDragHelper;
-
-    private EventTrigger mockedEventTrigger;
-
-    private WXComponent c1;
-    private WXComponent c2;
-    private WXComponent c3;
-
-    private List<WXComponent> mFakeDataSource;
-
-    public static WXListComponent create(WXVContainer parent) throws IllegalAccessException, InstantiationException, InvocationTargetException {
-        return create(parent,new WXListDomObject());
-    }
-
-    public static WXListComponent create(WXVContainer parent, WXDomObject dom) throws IllegalAccessException, InstantiationException, InvocationTargetException {
-        return (WXListComponent) new SimpleComponentHolder(WXListComponent.class).createInstance(WXSDKInstanceTest.createInstance(), dom, parent);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        WXDiv div = WXDivTest.create();
-        ComponentTest.create(div);
-        listComponent = create(div);
-        ComponentTest.create(listComponent);
-
-        fakeCell = new WXCell(WXSDKInstanceTest.createInstance(),new TestDomObject(),null,false);
-
-        c1 = new WXCell(WXSDKInstanceTest.createInstance(),new TestDomObject(),null,false);
-        c2 = new WXCell(WXSDKInstanceTest.createInstance(),new TestDomObject(),null,false);
-        c3 = new WXCell(WXSDKInstanceTest.createInstance(),new TestDomObject(),null,false);
-
-        mFakeDataSource = new ArrayList<>();
-        mFakeDataSource.add(c1);
-        mFakeDataSource.add(c2);
-        mFakeDataSource.add(c3);
-
-        mockedEventTrigger = mock(EventTrigger.class);
-
-        mFakeDragHelper = new DefaultDragHelper(mFakeDataSource,listComponent.getHostView().getInnerView(), mockedEventTrigger);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        listComponent.destroy();
-    }
-
-    @Test
-    public void onDragStart() throws Exception {
-        WXComponent c = new WXCell(WXSDKInstanceTest.createInstance(),new TestDomObject(),null,false);
-        mFakeDragHelper.onDragStart(c,3);
-        verify(mockedEventTrigger).triggerEvent(eq("dragstart"),anyMap());
-    }
-
-    @Test
-    public void onDragEnd() throws Exception {
-        WXComponent c = new WXCell(WXSDKInstanceTest.createInstance(),new TestDomObject(),null,false);
-        mFakeDragHelper.onDragEnd(c,1,2);
-        verify(mockedEventTrigger).triggerEvent(eq("dragend"),anyMap());
-    }
-
-    @Test
-    public void onDragging() throws Exception {
-        assertEquals(mFakeDataSource.get(0),c1);
-        assertEquals(mFakeDataSource.get(1),c2);
-
-        mFakeDragHelper.onDragging(0,1);
-
-        assertEquals(mFakeDataSource.get(0),c2);
-        assertEquals(mFakeDataSource.get(1),c1);
-    }
-
-
-}
\ No newline at end of file
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/list/WXListComponentTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/list/WXListComponentTest.java
deleted file mode 100644
index feb2b05..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/component/list/WXListComponentTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.component.list;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.ui.SimpleComponentHolder;
-import com.taobao.weex.ui.component.ComponentTest;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXDiv;
-import com.taobao.weex.ui.component.WXDivTest;
-import com.taobao.weex.ui.component.WXHeaderTest;
-import com.taobao.weex.ui.component.WXVContainer;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by sospartan on 8/29/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXListComponentTest {
-
-  WXListComponent component;
-
-  public static WXListComponent create(WXVContainer parent) throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return create(parent,new WXListDomObject());
-  }
-
-  public static WXListComponent create(WXVContainer parent, WXDomObject dom) throws IllegalAccessException, InstantiationException, InvocationTargetException {
-    return (WXListComponent) new SimpleComponentHolder(WXListComponent.class).createInstance(WXSDKInstanceTest.createInstance(), dom, parent);
-  }
-
-  @Before
-  public void setUp() throws Exception {
-    WXDiv div = WXDivTest.create();
-    ComponentTest.create(div);
-    component = create(div);
-    ComponentTest.create(component);
-  }
-
-  @Test
-  public void testAddChild() throws Exception {
-    WXComponent child = WXDivTest.create(component);
-    ComponentTest.create(child);
-    component.addChild(child);
-
-    child = WXHeaderTest.create(component);
-    ComponentTest.create(child);
-    component.addChild(child);
-
-  }
-
-  @Test
-  public void testScrollTo() throws Exception {
-    WXComponent child = WXDivTest.create(component);
-    ComponentTest.create(child);
-    component.addChild(child);
-
-    child = WXHeaderTest.create(component);
-    ComponentTest.create(child);
-    component.addChild(child);
-
-    Map<String, Object> options = new HashMap<>(2);
-    options.put("offset", 10);
-    options.put("animated", false);
-    component.scrollTo(child,options);
-  }
-
-  @Test
-  public void testAppear() throws Exception {
-    WXComponent child = WXDivTest.create(component);
-    ComponentTest.create(child);
-    component.addChild(child);
-
-    component.bindAppearEvent(child);
-
-    component.notifyAppearStateChange(0,0,0,10);
-  }
-
-  @Test
-  public void testParseTransforms() throws Exception {
-    WXDiv div = WXDivTest.create();
-    ComponentTest.create(div);
-
-    WXDomObject dom = new WXListDomObject();
-    dom.getAttrs().put(WXListComponent.TRANSFORM,"scale(0.9,0.8);translate(10,20);opacity(0.5);rotate(100)");
-    component = create(div,dom);
-    ComponentTest.create(component);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    component.destroy();
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXMetaModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/module/WXMetaModuleTest.java
deleted file mode 100644
index d58a0dc..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXMetaModuleTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.bridge.WXBridgeManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static junit.framework.Assert.assertTrue;
-
-/**
- * Created by zhengshihan on 16/12/21.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-@PrepareForTest(WXBridgeManager.class)
-public class WXMetaModuleTest {
-
-    WXMetaModule mMeta;
-    @Before
-    public void setUp() throws Exception {
-        mMeta = new WXMetaModule();
-        mMeta.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-
-    }
-
-    @Test
-    public void setViewport() throws Exception {
-        JSONObject jsonObject  = new JSONObject();
-        jsonObject.put(WXMetaModule.WIDTH,640);
-        mMeta.setViewport(jsonObject.toString());
-        assertTrue(mMeta.mWXSDKInstance.getInstanceViewPortWidth() == 640);
-
-        jsonObject.put(WXMetaModule.WIDTH,320.5);
-        mMeta.setViewport(jsonObject.toString());
-        assertTrue(mMeta.mWXSDKInstance.getInstanceViewPortWidth() == 320);
-
-        jsonObject.put(WXMetaModule.WIDTH,"-200");
-        mMeta.setViewport(jsonObject.toString());
-        assertTrue(mMeta.mWXSDKInstance.getInstanceViewPortWidth() == 320);
-
-        jsonObject.put(WXMetaModule.WIDTH,"error");
-        mMeta.setViewport(jsonObject.toString());
-        assertTrue(mMeta.mWXSDKInstance.getInstanceViewPortWidth() == 320);
-
-
-        mMeta.setViewport("ads");
-        assertTrue(mMeta.mWXSDKInstance.getInstanceViewPortWidth() == 320);
-    }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXModalUIModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/module/WXModalUIModuleTest.java
deleted file mode 100644
index 17d3fba..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXModalUIModuleTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.bridge.JSCallback;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 7/28/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*","org.json.*" })
-@PrepareForTest()
-public class WXModalUIModuleTest {
-
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-
-  WXModalUIModule module;
-
-  @Before
-  public void setUp() throws Exception {
-    module = new WXModalUIModule();
-    module.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-
-  }
-
-  @Test
-  public void testToast() throws Exception {
-    module.toast("{}");
-  }
-
-  @Test
-  public void testAlert() throws Exception {
-    JSCallback callback = Mockito.mock(JSCallback.class);
-    module.alert("{}",callback);
-
-  }
-
-  @Test
-  public void testConfirm() throws Exception {
-    JSCallback callback = Mockito.mock(JSCallback.class);
-    module.confirm("{}",callback);
-  }
-
-  @Test
-  public void testPrompt() throws Exception {
-    JSCallback callback = Mockito.mock(JSCallback.class);
-    module.prompt("{}",callback);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXTimerModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/module/WXTimerModuleTest.java
deleted file mode 100644
index 7fe508c..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXTimerModuleTest.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.when;
-
-import android.os.Handler;
-import android.os.Message;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.InitConfig;
-import com.taobao.weex.WXSDKEngine;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.bridge.WXBridgeManager;
-import com.taobao.weex.bridge.WXBridgeManagerTest;
-import com.taobao.weex.common.WXThread;
-import java.util.concurrent.TimeUnit;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLooper;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class)
-@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
-@PrepareForTest(WXBridgeManager.class)
-public class WXTimerModuleTest {
-
-  public final static int VALID_FUNC_ID = 20;
-  public final static int NO_CACHING_FUNC_ID = 565654;
-  public final static int INVALID_FUNC_ID = 0;
-  public final static int DELAY = 50;
-  public final static int IMMEDIATELY = 0;
-  public final static int INVALID_DELAY = -50;
-
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-  WXTimerModule module;
-  ShadowLooper mLooper;
-
-  @Before
-  public void setup() throws Exception {
-    WXSDKEngine.initialize(RuntimeEnvironment.application, new InitConfig.Builder().build());
-    WXBridgeManager bridge = Mockito.mock(WXBridgeManager.class);
-    when(bridge.getJSLooper()).thenReturn(new WXThread("js").getLooper());
-    WXBridgeManagerTest.setBridgeManager(bridge);
-
-    module = Mockito.spy(new WXTimerModule());
-    module.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-    Handler handler = new Handler(WXBridgeManager.getInstance().getJSLooper(), module);
-    mLooper = Shadows.shadowOf(handler.getLooper());
-    module.setHandler(handler);
-  }
-
-  @Test
-  public void testSetTimeoutDelay() throws Exception {
-    module.setTimeout(VALID_FUNC_ID, DELAY);
-    mLooper.idle(DELAY);
-    Mockito.verify(module, times(1)).handleMessage(any(Message.class));
-  }
-
-  @Test
-  public void testSetTimeoutImmediately() throws Exception {
-    module.setTimeout(VALID_FUNC_ID, IMMEDIATELY);
-    mLooper.idle(IMMEDIATELY);
-    Mockito.verify(module, times(1)).handleMessage(any(Message.class));
-  }
-
-  @SuppressWarnings("Range")
-  @Test
-  public void testSetTimeoutError1() throws Exception {
-    module.setTimeout(INVALID_FUNC_ID, DELAY);
-    mLooper.idle(DELAY);
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-
-  @SuppressWarnings("Range")
-  @Test
-  public void testSetTimeoutError2() throws Exception {
-    module.setTimeout(VALID_FUNC_ID, INVALID_DELAY);
-    mLooper.runToEndOfTasks();
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-
-  @SuppressWarnings("Range")
-  @Test
-  public void testSetIntervalError1() throws Exception {
-    module.setInterval(INVALID_FUNC_ID, DELAY);
-    mLooper.idle(DELAY);
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-
-  @SuppressWarnings("Range")
-  @Test
-  public void testSetIntervalError2() throws Exception {
-    module.setInterval(VALID_FUNC_ID, INVALID_DELAY);
-    mLooper.runToEndOfTasks();
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-
-  @Test
-  public void testSetIntervalImmediately() throws Exception {
-    long start, end, duration;
-    module.setInterval(VALID_FUNC_ID, DELAY);
-
-    start = mLooper.getScheduler().getCurrentTime();
-    mLooper.runOneTask();
-    end = mLooper.getScheduler().getCurrentTime();
-    duration = end - start;
-
-    assertThat(duration, is((long) DELAY));
-
-    mLooper.runOneTask();
-    mLooper.runOneTask();
-    mLooper.runOneTask();
-    mLooper.runOneTask();
-    Mockito.verify(module, times(5)).handleMessage(any(Message.class));
-  }
-
-  @Test
-  public void testSetIntervalDelay() {
-    long start, end, duration;
-    module.setInterval(VALID_FUNC_ID, DELAY);
-
-    start = mLooper.getScheduler().getCurrentTime();
-    mLooper.runOneTask();
-    end = mLooper.getScheduler().getCurrentTime();
-    duration = end - start;
-
-    assertThat(duration, is((long) DELAY));
-
-    mLooper.runOneTask();
-    mLooper.runOneTask();
-    Mockito.verify(module, times(3)).handleMessage(any(Message.class));
-  }
-
-  @Test
-  public void testClearTimeout() throws Exception {
-    module.setTimeout(VALID_FUNC_ID, DELAY);
-    module.clearTimeout(VALID_FUNC_ID);
-    mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-
-  @Test
-  public void testClearInterval() throws Exception {
-    module.setInterval(VALID_FUNC_ID, DELAY);
-    module.clearInterval(VALID_FUNC_ID);
-    mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-
-  @Test
-  public void setClearTimeout2(){
-    module.setTimeout(NO_CACHING_FUNC_ID, DELAY);
-    module.clearTimeout(NO_CACHING_FUNC_ID);
-    mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-
-  @Test
-  public void setClearInterval2(){
-    module.setInterval(NO_CACHING_FUNC_ID, DELAY);
-    module.clearInterval(NO_CACHING_FUNC_ID);
-    mLooper.idle(DELAY, TimeUnit.MILLISECONDS);
-    Mockito.verify(module, never()).handleMessage(any(Message.class));
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXWebViewModuleTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/module/WXWebViewModuleTest.java
deleted file mode 100644
index acb8e86..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/module/WXWebViewModuleTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.module;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKInstanceTest;
-import com.taobao.weex.bridge.WXBridgeManager;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 7/28/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-@PrepareForTest(WXBridgeManager.class)
-public class WXWebViewModuleTest {
-  WXWebViewModule module;
-
-  @Before
-  public void setUp() throws Exception {
-    module = new WXWebViewModule();
-    module.mWXSDKInstance = WXSDKInstanceTest.createInstance();
-  }
-
-  @Test
-  public void testGoBack() throws Exception {
-    module.goBack("");
-  }
-
-  @Test
-  public void testGoForward() throws Exception {
-    module.goForward("");
-  }
-
-  @Test
-  public void testReload() throws Exception {
-    module.reload("");
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/view/WXCirclePageAdapterTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/view/WXCirclePageAdapterTest.java
deleted file mode 100644
index 90b96f7..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/view/WXCirclePageAdapterTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.app.Activity;
-import android.support.v4.view.ViewPager;
-import android.view.View;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.TestActivity;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 9/7/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXCirclePageAdapterTest {
-
-  WXCirclePageAdapter adapter;
-  View child;
-
-  @Before
-  public void setUp() throws Exception {
-    adapter = new WXCirclePageAdapter();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-  }
-
-  @Test
-  public void testAddPageView() throws Exception {
-    Activity activity = Robolectric.setupActivity(TestActivity.class);
-    child = new View(activity);
-    adapter.addPageView(child);
-    child = new View(activity);
-    adapter.addPageView(child);
-    child = new View(activity);
-    adapter.addPageView(child);
-
-    assertEquals(adapter.getRealCount(),3);
-  }
-
-  @Test
-  public void testRemovePageView() throws Exception {
-    testAddPageView();
-    adapter.removePageView(child);
-    assertEquals(adapter.getRealCount(),2);
-  }
-
-
-  @Test
-  public void testInstantiateItem() throws Exception {
-    testAddPageView();
-    ViewPager viewPager = new ViewPager(child.getContext());
-    viewPager.setAdapter(adapter);
-    Object obj = adapter.instantiateItem(viewPager,adapter.getRealCount());
-    assertEquals(child,obj);
-  }
-
-  @Test
-  public void testReplacePageView() throws Exception {
-    testAddPageView();
-    View relace = new View(child.getContext());
-
-    adapter.replacePageView(child,relace);
-
-    assertEquals(adapter.getRealCount(),3);
-    
-  }
-
-  @Test
-  public void testGetRealPosition() throws Exception {
-    testAddPageView();
-    assertEquals(adapter.getRealPosition(0), adapter.getRealCount() - 1);
-    assertEquals(adapter.getRealPosition(1), 0);
-    assertEquals(adapter.getRealPosition(adapter.getRealCount() + 1), 0);
-    assertEquals(adapter.getRealPosition(100), -1);
-    assertEquals(adapter.getRealPosition(-1), -1);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/view/WXScrollViewTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/view/WXScrollViewTest.java
deleted file mode 100644
index 3873aa1..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/view/WXScrollViewTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import android.app.Activity;
-import android.view.MotionEvent;
-import android.view.View;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.TestActivity;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 9/7/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXScrollViewTest {
-
-  WXScrollView view;
-
-  static final int[] EVENTS = {MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_UP};
-
-  @Before
-  public void setUp() throws Exception {
-    Activity activity = Robolectric.setupActivity(TestActivity.class);
-    view = new WXScrollView(activity);
-    View child = new View(activity);
-    view.addView(child);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    view.destroy();
-  }
-
-  @Test
-  public void testDispatchTouchEvent() throws Exception {
-    for(int action:EVENTS) {
-      MotionEvent event = MotionEvent.obtain(100, 100, action,
-          10, 10, 0);
-      view.dispatchTouchEvent(event);
-      event.recycle();
-    }
-  }
-
-  @Test
-  public void testOnTouchEvent() throws Exception {
-    for(int action:EVENTS) {
-      MotionEvent event = MotionEvent.obtain(100, 100, action,
-          10, 10, 0);
-      view.onTouchEvent(event);
-      event.recycle();
-    }
-  }
-
-  @Test
-  public void testOnScrollChanged() throws Exception {
-    view.onScrollChanged(0,10,0,20);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/view/WXWebViewTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/view/WXWebViewTest.java
deleted file mode 100644
index 7b8b5cd..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/view/WXWebViewTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view;
-
-import static org.junit.Assert.assertNotNull;
-
-import android.app.Activity;
-import android.view.ViewGroup;
-import android.webkit.WebChromeClient;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.TestActivity;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.Shadows;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowWebView;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by sospartan on 9/7/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXWebViewTest {
-
-  IWebView view;
-  WebView webView;
-  ShadowWebView shadow;
-
-  @Before
-  public void setUp() throws Exception {
-    Activity activity = Robolectric.setupActivity(TestActivity.class);
-    view = new WXWebView(activity, null);
-    webView = (WebView)((ViewGroup)view.getView()).getChildAt(0);//first child
-    shadow = Shadows.shadowOf(webView);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    view.destroy();
-  }
-
-  @Test
-  public void testDestory() throws Exception {
-
-  }
-
-  @Test
-  public void testGetView() throws Exception {
-    assertNotNull(view);
-  }
-
-  @Test
-  public void testLoadUrl() throws Exception {
-    String url = "http://www.taobao.com";
-    view.loadUrl(url);
-    WebViewClient client = shadow.getWebViewClient();
-    client.onPageStarted(webView,url,null);
-    client.onPageFinished(webView,url);
-
-    WebChromeClient chromeClient = shadow.getWebChromeClient();
-    chromeClient.onProgressChanged(webView,10);
-    chromeClient.onProgressChanged(webView,100);
-    chromeClient.onReceivedTitle(webView,"test");
-
-  }
-
-  @Test
-  public void testLoadDataWithBaseURL() throws Exception {
-    String source = "<p><span>hello weex</span></p>";
-    view.loadDataWithBaseURL(source);
-  }
-
-
-  @Test
-  public void testReload() throws Exception {
-    view.reload();
-    testLoadUrl();
-    view.reload();
-  }
-
-  @Test
-  public void testGoBack() throws Exception {
-    testLoadUrl();
-    view.loadUrl("http://www.w3c.org");
-    view.goBack();
-  }
-
-  @Test
-  public void testGoForward() throws Exception {
-    testGoBack();
-    view.goForward();
-  }
-
-  @Test
-  public void testPostMessage() throws Exception {
-    Map<String, Object> msg = new HashMap<>();
-    msg.put("test1", 1);
-    msg.put("test2", "2");
-    view.postMessage(msg);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/view/border/BorderCornerTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/view/border/BorderCornerTest.java
deleted file mode 100644
index 827e632..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/view/border/BorderCornerTest.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.support.annotation.Nullable;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.*;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class BorderCornerTest {
-
-  private final static String TOP_LEFT = "TopLeft";
-  private final static String TOP_RIGHT = "TopRight";
-  private final static String BOTTOM_RIGHT = "BottomRight";
-  private final static String BOTTOM_LEFT = "BottomLeft";
-
-  private List<BorderCorner> borderCorners = new ArrayList<>();
-  private RectF borderBox = new RectF(0, 0, 400, 400);
-  private List<Float> radiusList = Arrays.asList(-10f, 0f, 10f, 25f, 50f, 75f, 150f);
-  private List<Float> preWidthList = Arrays.asList(-10f, 0f, 10f, 50f, 100f);
-  private List<Float> postWidthList = Arrays.asList(-10f, 0f, 10f, 50f, 100f);
-  private List<String> cornerList = Arrays.asList(TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT);
-
-  private
-  @Nullable
-  BorderCorner createBorderCorner(String corner, float
-      radius, float preWidth, float postWidth, RectF borderBox) {
-    switch (corner) {
-      case TOP_LEFT:
-        return new TopLeftCorner(radius, preWidth, postWidth, borderBox);
-      case TOP_RIGHT:
-        return new TopRightCorner(radius, preWidth, postWidth, borderBox);
-      case BOTTOM_RIGHT:
-        return new BottomRightCorner(radius, preWidth, postWidth, borderBox);
-      case BOTTOM_LEFT:
-        return new BottomLeftCorner(radius, preWidth, postWidth, borderBox);
-      default:
-        return null;
-    }
-  }
-
-  @Before
-  public void setUp() throws Exception {
-
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    borderCorners.clear();
-  }
-
-  @Test
-  public void testHasOuterCorner() throws Exception {
-    for (float preWidth : preWidthList) {
-      for (float postWidth : postWidthList) {
-        for (String corner : cornerList) {
-          assertThat(createBorderCorner(corner, 0f, preWidth, postWidth, borderBox).hasOuterCorner(), is(false));
-          assertThat(createBorderCorner(corner, 50f, preWidth, postWidth, borderBox)
-                         .hasOuterCorner(), is(true));
-          assertThat(createBorderCorner(corner, -10f, preWidth, postWidth, borderBox)
-                         .hasOuterCorner(), is(false));
-        }
-      }
-    }
-  }
-
-  @Test
-  public void testHasInnerCorner() throws Exception {
-    for (String corner : cornerList) {
-      for (float preWidth : preWidthList) {
-        for (float postWidth : postWidthList) {
-          assertThat(createBorderCorner(corner, -10, preWidth, postWidth, borderBox).hasInnerCorner()
-              , is(false));
-          assertThat(createBorderCorner(corner, 0, preWidth, postWidth, borderBox)
-                         .hasInnerCorner()
-              , is(false));
-        }
-      }
-      assertThat(createBorderCorner(corner, 25, -10, -10, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, -10, 0, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, -10, 10, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, -10, 50, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 0, -10, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 0, 0, borderBox).hasInnerCorner()
-          , is(true));
-      assertThat(createBorderCorner(corner, 25, 0, 10, borderBox).hasInnerCorner()
-          , is(true));
-      assertThat(createBorderCorner(corner, 25, 0, 50, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 10, -10, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 10, 0, borderBox).hasInnerCorner()
-          , is(true));
-      assertThat(createBorderCorner(corner, 25, 10, 10, borderBox).hasInnerCorner()
-          , is(true));
-      assertThat(createBorderCorner(corner, 25, 10, 50, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 50, -10, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 50, 0, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 50, 10, borderBox).hasInnerCorner()
-          , is(false));
-      assertThat(createBorderCorner(corner, 25, 50, 50, borderBox).hasInnerCorner()
-          , is(false));
-    }
-  }
-
-  @Test
-  public void testGetCornerStart() throws Exception {
-    PointF topLeft = createBorderCorner(TOP_LEFT, 25, 10, 50, borderBox)
-        .getCornerStart();
-    assertThat(topLeft.x, is(5f));
-    assertThat(topLeft.y, is(25f));
-    PointF topRight = createBorderCorner(TOP_RIGHT, 25, 10, 50, borderBox)
-        .getCornerStart();
-    assertThat(topRight.x, is(375f));
-    assertThat(topRight.y, is(5f));
-    PointF bottomRight = createBorderCorner(BOTTOM_RIGHT, 25, 10, 50, borderBox)
-        .getCornerStart();
-    assertThat(bottomRight.x, is(395f));
-    assertThat(bottomRight.y, is(375f));
-    PointF bottomLeft = createBorderCorner(BOTTOM_LEFT, 25, 10, 50, borderBox)
-        .getCornerStart();
-    assertThat(bottomLeft.x, is(25f));
-    assertThat(bottomLeft.y, is(395f));
-  }
-
-  @Test
-  public void testGetCornerEnd() throws Exception {
-    PointF topLeft = createBorderCorner(TOP_LEFT, 0, 10, 50, borderBox)
-        .getCornerEnd();
-    assertThat(topLeft.x, is(5f));
-    assertThat(topLeft.y, is(25f));
-    PointF topRight = createBorderCorner(TOP_RIGHT, 0, 10, 50, borderBox)
-        .getCornerEnd();
-    assertThat(topRight.x, is(375f));
-    assertThat(topRight.y, is(5f));
-    PointF bottomRight = createBorderCorner(BOTTOM_RIGHT, 0, 10, 50, borderBox)
-        .getCornerEnd();
-    assertThat(bottomRight.x, is(395f));
-    assertThat(bottomRight.y, is(375f));
-    PointF bottomLeft = createBorderCorner(BOTTOM_LEFT, 0, 10, 50, borderBox)
-        .getCornerEnd();
-    assertThat(bottomLeft.x, is(25f));
-    assertThat(bottomLeft.y, is(395f));
-  }
-
-  @Test
-  public void testGetRoundCornerStart() throws Exception {
-    PointF topLeft = createBorderCorner(TOP_LEFT, 25, 10, 50, borderBox)
-        .getRoundCornerStart();
-    assertThat(topLeft.x, is(5f));
-    assertThat(topLeft.y, is(25f));
-    PointF topRight = createBorderCorner(TOP_RIGHT, 25, 10, 50, borderBox)
-        .getRoundCornerStart();
-    assertThat(topRight.x, is(375f));
-    assertThat(topRight.y, is(5f));
-    PointF bottomRight = createBorderCorner(BOTTOM_RIGHT, 25, 10, 50, borderBox)
-        .getRoundCornerStart();
-    assertThat(bottomRight.x, is(395f));
-    assertThat(bottomRight.y, is(375f));
-    PointF bottomLeft = createBorderCorner(BOTTOM_LEFT, 25, 10, 50, borderBox)
-        .getRoundCornerStart();
-    assertThat(bottomLeft.x, is(25f));
-    assertThat(bottomLeft.y, is(395f));
-  }
-
-  @Test
-  public void testGetRoundCornerEnd() throws Exception {
-    PointF topLeft = createBorderCorner(TOP_LEFT, 25, 10, 50, borderBox)
-        .getRoundCornerEnd();
-    assertThat(topLeft.x, is(25f));
-    assertThat(topLeft.y, is(25f));
-    PointF topRight = createBorderCorner(TOP_RIGHT, 25, 10, 50, borderBox)
-        .getRoundCornerEnd();
-    assertThat(topRight.x, is(375f));
-    assertThat(topRight.y, is(25f));
-    PointF bottomRight = createBorderCorner(BOTTOM_RIGHT, 25, 10, 50, borderBox)
-        .getRoundCornerEnd();
-    assertThat(bottomRight.x, is(375f));
-    assertThat(bottomRight.y, is(375f));
-    PointF bottomLeft = createBorderCorner(BOTTOM_LEFT, 25, 10, 50, borderBox)
-        .getRoundCornerEnd();
-    assertThat(bottomLeft.x, is(25f));
-    assertThat(bottomLeft.y, is(375f));
-  }
-
-  @Test
-  public void testGetSharpCornerVertex() throws Exception {
-    PointF topLeft = createBorderCorner(TOP_LEFT, 0, 10, 50, borderBox)
-        .getSharpCornerVertex();
-    assertThat(topLeft.x, is(5f));
-    assertThat(topLeft.y, is(25f));
-    PointF topRight = createBorderCorner(TOP_RIGHT, 0, 10, 50, borderBox)
-        .getSharpCornerVertex();
-    assertThat(topRight.x, is(375f));
-    assertThat(topRight.y, is(5f));
-    PointF bottomRight = createBorderCorner(BOTTOM_RIGHT, 0, 10, 50, borderBox)
-        .getSharpCornerVertex();
-    assertThat(bottomRight.x, is(395f));
-    assertThat(bottomRight.y, is(375f));
-    PointF bottomLeft = createBorderCorner(BOTTOM_LEFT, 0, 10, 50, borderBox)
-        .getSharpCornerVertex();
-    assertThat(bottomLeft.x, is(25f));
-    assertThat(bottomLeft.y, is(395f));
-  }
-
-  @Test
-  public void testGetSharpCornerStart() throws Exception {
-    PointF topLeft = createBorderCorner(TOP_LEFT, 0, 10, 50, borderBox)
-        .getSharpCornerStart();
-    assertThat(topLeft.x, is(0f));
-    assertThat(topLeft.y, is(25f));
-    PointF topRight = createBorderCorner(TOP_RIGHT, 0, 10, 50, borderBox)
-        .getSharpCornerStart();
-    assertThat(topRight.x, is(375f));
-    assertThat(topRight.y, is(0f));
-    PointF bottomRight = createBorderCorner(BOTTOM_RIGHT, 0, 10, 50, borderBox)
-        .getSharpCornerStart();
-    assertThat(bottomRight.x, is(400f));
-    assertThat(bottomRight.y, is(375f));
-    PointF bottomLeft = createBorderCorner(BOTTOM_LEFT, 0, 10, 50, borderBox)
-        .getSharpCornerStart();
-    assertThat(bottomLeft.x, is(25f));
-    assertThat(bottomLeft.y, is(400f));
-  }
-
-  @Test
-  public void testGetSharpCornerEnd() throws Exception {
-    PointF topLeft = createBorderCorner(TOP_LEFT, 0, 10, 50, borderBox)
-        .getSharpCornerEnd();
-    assertThat(topLeft.x, is(5f));
-    assertThat(topLeft.y, is(0f));
-    PointF topRight = createBorderCorner(TOP_RIGHT, 0, 10, 50, borderBox)
-        .getSharpCornerEnd();
-    assertThat(topRight.x, is(400f));
-    assertThat(topRight.y, is(5f));
-    PointF bottomRight = createBorderCorner(BOTTOM_RIGHT, 0, 10, 50, borderBox)
-        .getSharpCornerEnd();
-    assertThat(bottomRight.x, is(395f));
-    assertThat(bottomRight.y, is(400f));
-    PointF bottomLeft = createBorderCorner(BOTTOM_LEFT, 0, 10, 50, borderBox)
-        .getSharpCornerEnd();
-    assertThat(bottomLeft.x, is(0f));
-    assertThat(bottomLeft.y, is(395f));
-  }
-
-  @Test
-  public void testGetOvalIfInnerCornerExist() throws Exception {
-    RectF topLeft = createBorderCorner(TOP_LEFT, 100, 10, 50, borderBox)
-        .getOvalIfInnerCornerExist();
-    assertThat(topLeft, is(new RectF(5, 25, 195, 175)));
-    RectF topRight = createBorderCorner(TOP_RIGHT, 100, 10, 50, borderBox)
-        .getOvalIfInnerCornerExist();
-    assertThat(topRight, is(new RectF(225, 5, 375, 195)));
-    RectF bottomRight = createBorderCorner(BOTTOM_RIGHT, 100, 10, 50, borderBox)
-        .getOvalIfInnerCornerExist();
-    assertThat(bottomRight, is(new RectF(205, 225, 395, 375)));
-    RectF bottomLeft = createBorderCorner(BOTTOM_LEFT, 100, 10, 50, borderBox)
-        .getOvalIfInnerCornerExist();
-    assertThat(bottomLeft, is(new RectF(25, 205, 175, 395)));
-  }
-
-  @Test
-  public void testGetOvalIfInnerCornerNotExist() throws Exception {
-    RectF topLeft = createBorderCorner(TOP_LEFT, 50, 10, 50, borderBox).getOvalIfInnerCornerNotExist();
-    assertThat(topLeft, is(new RectF(25, 25, 75, 75)));
-    RectF topRight = createBorderCorner(TOP_RIGHT, 50, 10, 50, borderBox).getOvalIfInnerCornerNotExist();
-    assertThat(topRight, is(new RectF(325, 25, 375, 75)));
-    RectF bottomRight = createBorderCorner(BOTTOM_RIGHT, 50, 10, 50, borderBox).getOvalIfInnerCornerNotExist();
-    assertThat(bottomRight, is(new RectF(325, 325, 375, 375)));
-    RectF bottomLeft = createBorderCorner(BOTTOM_LEFT, 50, 10, 50, borderBox)
-        .getOvalIfInnerCornerNotExist();
-    assertThat(bottomLeft, is(new RectF(25, 325, 75, 375)));
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/view/border/BorderDrawableTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/view/border/BorderDrawableTest.java
deleted file mode 100644
index 49caafa..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/view/border/BorderDrawableTest.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.border;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-
-import com.taobao.weex.utils.WXResourceUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class BorderDrawableTest {
-
-  @Before
-  public void setUp() throws Exception {
-
-  }
-
-  @Test
-  public void testGetOpacity() throws Exception {
-    BorderDrawable opaque = new BorderDrawable();
-    opaque.setColor(Color.GREEN);
-    assertThat(opaque.getOpacity(), is(PixelFormat.OPAQUE));
-
-    BorderDrawable transparent = new BorderDrawable();
-    transparent.setColor(WXResourceUtils.getColor("#00ff0000"));
-    assertThat(transparent.getOpacity(), is(PixelFormat.TRANSPARENT));
-
-    BorderDrawable half = new BorderDrawable();
-    half.setColor(WXResourceUtils.getColor("#aaff0000"));
-    assertThat(half.getOpacity(), is(PixelFormat.TRANSLUCENT));
-
-    BorderDrawable changeAlpha = new BorderDrawable();
-    changeAlpha.setColor(Color.RED);
-    changeAlpha.setAlpha(15);
-    assertThat(changeAlpha.getOpacity(), is(PixelFormat.TRANSLUCENT));
-  }
-
-  @Test
-  public void testBorderWidth() throws Exception {
-    BorderDrawable none = new BorderDrawable();
-    assertThat(none.getBorderWidth(Spacing.ALL), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderWidth(Spacing.LEFT), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderWidth(Spacing.RIGHT), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderWidth(Spacing.TOP), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderWidth(Spacing.BOTTOM), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-
-    BorderDrawable full = new BorderDrawable();
-    full.setBorderWidth(Spacing.ALL, 12);
-    assertThat(full.getBorderWidth(Spacing.ALL), is(12f));
-    assertThat(full.getBorderWidth(Spacing.LEFT), is(12f));
-    assertThat(full.getBorderWidth(Spacing.RIGHT), is(12f));
-    assertThat(full.getBorderWidth(Spacing.TOP), is(12f));
-    assertThat(full.getBorderWidth(Spacing.BOTTOM), is(12f));
-
-    BorderDrawable noneAndPart = new BorderDrawable();
-    noneAndPart.setBorderWidth(Spacing.LEFT, 5);
-    noneAndPart.setBorderWidth(Spacing.TOP, 12);
-    assertThat(noneAndPart.getBorderWidth(Spacing.LEFT), is(5f));
-    assertThat(noneAndPart.getBorderWidth(Spacing.RIGHT), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(noneAndPart.getBorderWidth(Spacing.TOP), is(12f));
-    assertThat(noneAndPart.getBorderWidth(Spacing.BOTTOM), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-
-    BorderDrawable fullAndPart = new BorderDrawable();
-    fullAndPart.setBorderWidth(Spacing.ALL, 5);
-    fullAndPart.setBorderWidth(Spacing.LEFT, 12);
-    fullAndPart.setBorderWidth(Spacing.TOP, 19);
-    assertThat(fullAndPart.getBorderWidth(Spacing.LEFT), is(12f));
-    assertThat(fullAndPart.getBorderWidth(Spacing.RIGHT), is(5f));
-    assertThat(fullAndPart.getBorderWidth(Spacing.TOP), is(19f));
-    assertThat(fullAndPart.getBorderWidth(Spacing.BOTTOM), is(5f));
-
-    BorderDrawable partAndFull = new BorderDrawable();
-    partAndFull.setBorderWidth(Spacing.LEFT, 12);
-    partAndFull.setBorderWidth(Spacing.ALL, 5);
-    assertThat(partAndFull.getBorderWidth(Spacing.ALL), is(5f));
-    assertThat(partAndFull.getBorderWidth(Spacing.LEFT), is(5f));
-    assertThat(partAndFull.getBorderWidth(Spacing.RIGHT), is(5f));
-    assertThat(partAndFull.getBorderWidth(Spacing.TOP), is(5f));
-    assertThat(partAndFull.getBorderWidth(Spacing.BOTTOM), is(5f));
-  }
-
-  @Test
-  public void testBorderRadius() throws Exception {
-    BorderDrawable none = new BorderDrawable();
-    none.draw(new Canvas());
-    assertThat(none.getBorderRadius(BorderDrawable.BORDER_RADIUS_ALL), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(none.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-
-    BorderDrawable full = new BorderDrawable();
-    full.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 12);
-    full.setBounds(new Rect(0, 0, 400, 400));
-    full.draw(new Canvas());
-    assertThat(full.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is(12f));
-    assertThat(full.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is(12f));
-    assertThat(full.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is(12f));
-    assertThat(full.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS), is(12f));
-
-    BorderDrawable noneAndPart = new BorderDrawable();
-    noneAndPart.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 5);
-    noneAndPart.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 12);
-    noneAndPart.setBounds(new Rect(0, 0, 400, 400));
-    noneAndPart.draw(new Canvas());
-    assertThat(noneAndPart.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is(5f));
-    assertThat(noneAndPart.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-    assertThat(noneAndPart.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is(12f));
-    assertThat(noneAndPart.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS), is(BorderDrawable.DEFAULT_BORDER_WIDTH));
-
-    BorderDrawable fullAndPart = new BorderDrawable();
-    fullAndPart.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 5);
-    fullAndPart.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 12);
-    fullAndPart.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 19);
-    fullAndPart.setBounds(new Rect(0, 0, 400, 400));
-    fullAndPart.draw(new Canvas());
-    assertThat(fullAndPart.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is(12f));
-    assertThat(fullAndPart.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is(5f));
-    assertThat(fullAndPart.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is(19f));
-    assertThat(fullAndPart.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS), is(5f));
-
-    BorderDrawable partAndFull = new BorderDrawable();
-    partAndFull.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 12);
-    partAndFull.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 5);
-    partAndFull.setBounds(new Rect(0, 0, 400, 400));
-    partAndFull.draw(new Canvas());
-    assertThat(partAndFull.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is(5f));
-    assertThat(partAndFull.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is(5f));
-    assertThat(partAndFull.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is(5f));
-    assertThat(partAndFull.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS), is(5f));
-
-    BorderDrawable noOverLapping = new BorderDrawable();
-    noOverLapping.setBounds(new Rect(0, 0, 400, 400));
-    noOverLapping.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 0);
-    noOverLapping.draw(new Canvas());
-    assertThat(noOverLapping.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is(0f));
-    assertThat(noOverLapping.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is(0f));
-    assertThat(noOverLapping.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is(0f));
-    assertThat(noOverLapping.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS), is(0f));
-
-    BorderDrawable overlappingOneLine = new BorderDrawable();
-    overlappingOneLine.setBounds(new Rect(0, 0, 400, 400));
-    overlappingOneLine.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 300);
-    overlappingOneLine.setBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS, 200);
-    overlappingOneLine.draw(new Canvas());
-    assertThat(overlappingOneLine.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is(240f));
-    assertThat(overlappingOneLine.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is(160f));
-    assertThat(overlappingOneLine.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS), is
-        (0f));
-    assertThat(overlappingOneLine.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is
-        (0f));
-
-    BorderDrawable overlappingAdjoinLine = new BorderDrawable();
-    overlappingAdjoinLine.setBounds(new Rect(0, 0, 400, 400));
-    overlappingAdjoinLine.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 300);
-    overlappingAdjoinLine.setBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS, 200);
-    overlappingAdjoinLine.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 300);
-    overlappingAdjoinLine.setBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS, 50);
-    overlappingAdjoinLine.draw(new Canvas());
-    assertThat(overlappingAdjoinLine.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is
-        (240f));
-    assertThat(overlappingAdjoinLine.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is
-        (160f));
-    assertThat(overlappingAdjoinLine.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is
-        (240f));
-    assertThat(overlappingAdjoinLine.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS),
-               is(40f));
-
-    BorderDrawable overlappingNonadjoinLine = new BorderDrawable();
-    overlappingNonadjoinLine.setBounds(new Rect(0, 0, 400, 800));
-    overlappingNonadjoinLine.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 300);
-    overlappingNonadjoinLine.setBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS, 200);
-    overlappingNonadjoinLine.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 300);
-    overlappingNonadjoinLine.setBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS, 200);
-    overlappingNonadjoinLine.draw(new Canvas());
-    assertThat(overlappingNonadjoinLine.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS), is
-        (240f));
-    assertThat(overlappingNonadjoinLine.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS), is
-        (160f));
-    assertThat(overlappingNonadjoinLine.getBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS), is
-        (240f));
-    assertThat(overlappingNonadjoinLine.getBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS),
-               is(160f));
-
-    BorderDrawable overlappingThreeLines = new BorderDrawable();
-    overlappingThreeLines.setBounds(new Rect(0, 0, 400, 500));
-    overlappingThreeLines.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 300);
-    overlappingThreeLines.setBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS, 200);
-    overlappingThreeLines.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 600);
-    overlappingThreeLines.setBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS, 100);
-    overlappingThreeLines.draw(new Canvas());
-    assertEquals(300f * 4 / 7,
-                 overlappingThreeLines.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS),
-                 .00001f);
-    assertEquals(200f * 4 / 7, overlappingThreeLines.getBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS),
-                 .00001f);
-    assertEquals(600f * 4 / 7, overlappingThreeLines.getBorderRadius(BorderDrawable
-                                                                         .BORDER_BOTTOM_RIGHT_RADIUS),
-                 .00001f);
-    assertEquals(100f * 4 / 7, overlappingThreeLines.getBorderRadius(BorderDrawable
-                                                                         .BORDER_BOTTOM_LEFT_RADIUS),
-                 .00001f);
-
-    BorderDrawable overlappingFourLines = new BorderDrawable();
-    overlappingFourLines.setBounds(new Rect(0, 0, 400, 500));
-    overlappingFourLines.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 500);
-    overlappingFourLines.setBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS, 600);
-    overlappingFourLines.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 700);
-    overlappingFourLines.setBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS, 800);
-    overlappingFourLines.draw(new Canvas());
-    assertEquals(500f * 4 / 15,
-                 overlappingFourLines.getBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS),
-                 .0001f);
-    assertEquals(600f * 4 / 15, overlappingFourLines.getBorderRadius(BorderDrawable
-                                                                         .BORDER_TOP_RIGHT_RADIUS),
-                 .0001f);
-    assertEquals(700f * 4 / 15, overlappingFourLines.getBorderRadius(BorderDrawable
-                                                                         .BORDER_BOTTOM_RIGHT_RADIUS),
-                 .0001f);
-    assertEquals(800f * 4 / 15, overlappingFourLines.getBorderRadius(BorderDrawable
-                                                                         .BORDER_BOTTOM_LEFT_RADIUS),
-                 .0001f);
-  }
-
-  @Test
-  public void testBorderColor() throws Exception {
-    BorderDrawable none = new BorderDrawable();
-    assertThat(none.getBorderColor(Spacing.ALL), is(BorderDrawable.DEFAULT_BORDER_COLOR));
-    assertThat(none.getBorderColor(Spacing.LEFT), is(BorderDrawable.DEFAULT_BORDER_COLOR));
-    assertThat(none.getBorderColor(Spacing.RIGHT), is(BorderDrawable.DEFAULT_BORDER_COLOR));
-    assertThat(none.getBorderColor(Spacing.TOP), is(BorderDrawable.DEFAULT_BORDER_COLOR));
-    assertThat(none.getBorderColor(Spacing.BOTTOM), is(BorderDrawable.DEFAULT_BORDER_COLOR));
-
-    BorderDrawable full = new BorderDrawable();
-    full.setBorderColor(Spacing.ALL, Color.RED);
-    assertThat(full.getBorderColor(Spacing.ALL), is(Color.RED));
-    assertThat(full.getBorderColor(Spacing.LEFT), is(Color.RED));
-    assertThat(full.getBorderColor(Spacing.RIGHT), is(Color.RED));
-    assertThat(full.getBorderColor(Spacing.TOP), is(Color.RED));
-    assertThat(full.getBorderColor(Spacing.BOTTOM), is(Color.RED));
-
-    BorderDrawable noneAndPart = new BorderDrawable();
-    noneAndPart.setBorderColor(Spacing.LEFT, Color.BLUE);
-    noneAndPart.setBorderColor(Spacing.TOP, Color.GREEN);
-    assertThat(noneAndPart.getBorderColor(Spacing.LEFT), is(Color.BLUE));
-    assertThat(noneAndPart.getBorderColor(Spacing.RIGHT), is(BorderDrawable.DEFAULT_BORDER_COLOR));
-    assertThat(noneAndPart.getBorderColor(Spacing.TOP), is(Color.GREEN));
-    assertThat(noneAndPart.getBorderColor(Spacing.BOTTOM), is(BorderDrawable.DEFAULT_BORDER_COLOR));
-
-    BorderDrawable fullAndPart = new BorderDrawable();
-    fullAndPart.setBorderColor(Spacing.ALL, Color.BLUE);
-    fullAndPart.setBorderColor(Spacing.LEFT, Color.GREEN);
-    fullAndPart.setBorderColor(Spacing.TOP, Color.RED);
-    assertThat(fullAndPart.getBorderColor(Spacing.LEFT), is(Color.GREEN));
-    assertThat(fullAndPart.getBorderColor(Spacing.RIGHT), is(Color.BLUE));
-    assertThat(fullAndPart.getBorderColor(Spacing.TOP), is(Color.RED));
-    assertThat(fullAndPart.getBorderColor(Spacing.BOTTOM), is(Color.BLUE));
-
-    BorderDrawable partAndFull = new BorderDrawable();
-    partAndFull.setBorderColor(Spacing.LEFT, Color.RED);
-    partAndFull.setBorderColor(Spacing.ALL, Color.BLUE);
-    assertThat(partAndFull.getBorderColor(Spacing.ALL), is(Color.BLUE));
-    assertThat(partAndFull.getBorderColor(Spacing.LEFT), is(Color.BLUE));
-    assertThat(partAndFull.getBorderColor(Spacing.RIGHT), is(Color.BLUE));
-    assertThat(partAndFull.getBorderColor(Spacing.TOP), is(Color.BLUE));
-    assertThat(partAndFull.getBorderColor(Spacing.BOTTOM), is(Color.BLUE));
-
-  }
-
-  @Test
-  public void testBorderStyle() throws Exception {
-    BorderDrawable none = new BorderDrawable();
-    assertThat(none.getBorderStyle(Spacing.ALL), is(BorderStyle.SOLID.ordinal()));
-    assertThat(none.getBorderStyle(Spacing.LEFT), is(BorderStyle.SOLID.ordinal()));
-    assertThat(none.getBorderStyle(Spacing.RIGHT), is(BorderStyle.SOLID.ordinal()));
-    assertThat(none.getBorderStyle(Spacing.TOP), is(BorderStyle.SOLID.ordinal()));
-    assertThat(none.getBorderStyle(Spacing.BOTTOM), is(BorderStyle.SOLID.ordinal()));
-
-    BorderDrawable full = new BorderDrawable();
-    full.setBorderStyle(Spacing.ALL, BorderStyle.DOTTED.name());
-    assertThat(full.getBorderStyle(Spacing.ALL), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(full.getBorderStyle(Spacing.LEFT), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(full.getBorderStyle(Spacing.RIGHT), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(full.getBorderStyle(Spacing.TOP), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(full.getBorderStyle(Spacing.BOTTOM), is(BorderStyle.DOTTED.ordinal()));
-
-    BorderDrawable noneAndPart = new BorderDrawable();
-    noneAndPart.setBorderStyle(Spacing.LEFT, BorderStyle.DOTTED.name());
-    noneAndPart.setBorderStyle(Spacing.TOP, BorderStyle.DASHED.name());
-    assertThat(noneAndPart.getBorderStyle(Spacing.LEFT), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(noneAndPart.getBorderStyle(Spacing.RIGHT), is(BorderStyle.SOLID.ordinal()));
-    assertThat(noneAndPart.getBorderStyle(Spacing.TOP), is(BorderStyle.DASHED.ordinal()));
-    assertThat(noneAndPart.getBorderStyle(Spacing.BOTTOM), is(BorderStyle.SOLID.ordinal()));
-
-    BorderDrawable fullAndPart = new BorderDrawable();
-    fullAndPart.setBorderStyle(Spacing.ALL, BorderStyle.DASHED.name());
-    fullAndPart.setBorderStyle(Spacing.LEFT, BorderStyle.DOTTED.name());
-    fullAndPart.setBorderStyle(Spacing.TOP, BorderStyle.SOLID.name());
-    assertThat(fullAndPart.getBorderStyle(Spacing.LEFT), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(fullAndPart.getBorderStyle(Spacing.RIGHT), is(BorderStyle.DASHED.ordinal()));
-    assertThat(fullAndPart.getBorderStyle(Spacing.TOP), is(BorderStyle.SOLID.ordinal()));
-    assertThat(fullAndPart.getBorderStyle(Spacing.BOTTOM), is(BorderStyle.DASHED.ordinal()));
-
-    BorderDrawable partAndFull = new BorderDrawable();
-    partAndFull.setBorderStyle(Spacing.LEFT, BorderStyle.DASHED.name());
-    partAndFull.setBorderStyle(Spacing.ALL, BorderStyle.DOTTED.name());
-    assertThat(partAndFull.getBorderStyle(Spacing.ALL), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(partAndFull.getBorderStyle(Spacing.LEFT), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(partAndFull.getBorderStyle(Spacing.RIGHT), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(partAndFull.getBorderStyle(Spacing.TOP), is(BorderStyle.DOTTED.ordinal()));
-    assertThat(partAndFull.getBorderStyle(Spacing.BOTTOM), is(BorderStyle.DOTTED.ordinal()));
-  }
-
-  @Test
-  public void testIsRounded(){
-    BorderDrawable none = new BorderDrawable();
-    assertThat(none.isRounded(), is(false));
-
-    BorderDrawable full = new BorderDrawable();
-    full.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 12);
-    assertThat(full.isRounded(), is(true));
-
-    BorderDrawable noneAndPart = new BorderDrawable();
-    noneAndPart.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 5);
-    noneAndPart.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 12);
-    assertThat(noneAndPart.isRounded(), is(true));
-
-    BorderDrawable fullAndPart = new BorderDrawable();
-    fullAndPart.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 0);
-    fullAndPart.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 12);
-    fullAndPart.setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, 19);
-    assertThat(fullAndPart.isRounded(), is(true));
-
-    BorderDrawable partAndFull = new BorderDrawable();
-    partAndFull.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 12);
-    partAndFull.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 0);
-    assertThat(partAndFull.isRounded(), is(true));
-
-    BorderDrawable zeroAll = new BorderDrawable();
-    zeroAll.setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL, 0);
-    assertThat(zeroAll.isRounded(), is(false));
-
-    BorderDrawable zeroPart = new BorderDrawable();
-    zeroPart.setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, 0);
-    assertThat(zeroPart.isRounded(), is(false));
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/view/gesture/WXGestureTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/view/gesture/WXGestureTest.java
deleted file mode 100644
index 125f9d1..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/ui/view/gesture/WXGestureTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.ui.view.gesture;
-
-import android.view.MotionEvent;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.TestActivity;
-import com.taobao.weex.ui.component.ComponentTest;
-import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.ui.component.WXDivTest;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 27/09/2016.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-public class WXGestureTest {
-
-  WXGesture mGesture;
-  WXComponent component;
-  @Before
-  public void setUp() throws Exception {
-    component = WXDivTest.create();
-    ComponentTest.create(component);
-
-    component.addEvent(WXGestureType.LowLevelGesture.ACTION_CANCEL.toString());
-    component.addEvent(WXGestureType.LowLevelGesture.ACTION_DOWN.toString());
-    component.addEvent(WXGestureType.LowLevelGesture.ACTION_MOVE.toString());
-    component.addEvent(WXGestureType.LowLevelGesture.ACTION_UP.toString());
-
-    TestActivity activity = Robolectric.setupActivity(TestActivity.class);
-    mGesture = new WXGesture(component, activity);
-
-  }
-
-  @Test
-  public void testOnTouch() throws Exception {
-    MotionEvent event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(),MotionEvent.ACTION_DOWN,0,0,0);
-    mGesture.onTouch(component.getHostView(),event);
-
-    event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(),MotionEvent.ACTION_MOVE,0,0,0);
-    mGesture.onTouch(component.getHostView(),event);
-
-    event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(),MotionEvent.ACTION_UP,0,0,0);
-    mGesture.onTouch(component.getHostView(),event);
-
-    event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(),MotionEvent.ACTION_POINTER_UP,0,0,0);
-    mGesture.onTouch(component.getHostView(),event);
-
-    event = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis(),MotionEvent.ACTION_CANCEL,0,0,0);
-    mGesture.onTouch(component.getHostView(),event);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/FunctionParserTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/FunctionParserTest.java
deleted file mode 100644
index aa1c719..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/FunctionParserTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import org.junit.Test;
-
-import java.util.List;
-
-/**
- * Created by sospartan on 27/09/2016.
- */
-public class FunctionParserTest {
-
-  @Test
-  public void testParse() throws Exception {
-    List<Integer> s = new SingleFunctionParser<>("blur(5px)", new SingleFunctionParser.FlatMapper<Integer>() {
-      @Override
-      public Integer map(String raw) {
-        return WXUtils.getInteger(raw,0);
-      }
-    }).parse("blur");
-    System.out.println(s);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/TypefaceUtilTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/TypefaceUtilTest.java
deleted file mode 100644
index 7416b8d..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/TypefaceUtilTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXSDKInstanceTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 8/2/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-public class TypefaceUtilTest {
-
-  @Test
-  public void testPutFontDO() throws Exception {
-    FontDO font = new FontDO("test","url('local:///test')", WXSDKInstanceTest.createInstance());
-    TypefaceUtil.putFontDO(font);
-    assertEquals(TypefaceUtil.getFontDO("test").getUrl(),"local:///test");
-
-  }
-
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/WXFileUtilsTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/WXFileUtilsTest.java
deleted file mode 100644
index 64a0720..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXFileUtilsTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import java.io.File;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 8/2/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-@PrepareForTest()
-public class WXFileUtilsTest {
-
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-
-  @Test
-  public void testLoadFileContent() throws Exception {
-    File folder = new File("build/intermediates/bundles/debug/assets/");
-    if(!folder.exists()){
-      folder = new File("build/intermediates/bundles/debug/assets/");
-      folder.mkdirs();
-    }
-    File file = new File(folder,"test");
-    System.out.println(file.getAbsolutePath());
-    if(!file.exists()){
-      file.createNewFile();
-    }
-
-    WXFileUtils.loadAsset("test", RuntimeEnvironment.application);
-  }
-
-  @Test
-  public void testSaveFile() throws Exception {
-    WXFileUtils.saveFile("build/test","test".getBytes(),RuntimeEnvironment.application);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/WXJsonUtilsTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/WXJsonUtilsTest.java
deleted file mode 100644
index 92f64eb..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXJsonUtilsTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import com.alibaba.fastjson.JSON;
-import org.junit.Test;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 8/2/16.
- */
-public class WXJsonUtilsTest {
-
-
-  static class TestObj{
-    int a;
-
-    public int getA() {
-      return a;
-    }
-
-    public void setA(int a) {
-      this.a = a;
-    }
-  }
-
-  @Test
-  public void testGetList() throws Exception {
-    List<TestObj> list = WXJsonUtils.getList("[{'a':1},{'a':2}]",TestObj.class);
-
-    assertEquals(list.size(),2);
-    assertEquals(list.get(0).getA(),1);
-    assertEquals(list.get(1).getA(),2);
-
-    list = WXJsonUtils.getList("{}",TestObj.class);
-
-    assertEquals(list.size(),0);
-  }
-
-  @Test
-  public void testFromObjectToJSONString() throws Exception {
-    TestObj obj = new TestObj();
-    obj.a  = 1;
-    assertEquals(WXJsonUtils.fromObjectToJSONString(obj),"{\"a\":1}");
-    assertEquals(WXJsonUtils.fromObjectToJSONString(null),"null");
-    assertEquals(WXJsonUtils.fromObjectToJSONString(new Object()),"{}");
-
-    Map<String,Object> data = new HashMap<>();
-    data.put("a",536649655068L);
-    BigDecimal d = new BigDecimal(536649655068L);
-    data.put("d",d);
-    data.put("b",new Long(536649655068L));
-
-
-    Object resp = JSON.parse("[{\"offerId\":536449659068,\"subject\":\"jv2测试offer\",\"offerUnit\":\"千克\",\"price\":{\"price\":234.0},\"imageList\":[\"http://product.1688nongchanping.com/offer/7730-1503041G910-51.jpg\",\"http://product.1688nongchanping.com/offer/7730-1503041G910-51.jpg\",\"http://product.1688nongchanping.com/offer/140-150302120045.jpg\"],\"featureList\":[],\"companyInfo\":null,\"saleInfo\":{\"saledCount\":null,\"avaliableAmount\":100.0},\"detailURL\":\"<p>http://view.m.1688.com/cms/native/offerdetail.html?url=http://img02.taobaocdn.com/tfscom/TB18Z_5KVXXXXbAXXXXXXXXXXXX</p>\"},{\"offerId\":536489059003,\"subject\":\"jv 测试offer——detailURL\",\"offerUnit\":\"千克\",\"price\":{\"price\":12.0},\"imageList\":[\"http://product.1688nongchanping.com/offer/1139304780d4f14e57o.jpg\",\"http://product.1688nongchanping.com/offer/1139304780d4f14e57o.jpg\"],\"featureList\":[],\"companyInfo\":null,\"saleInfo\":{\"saledCount\":null,\"avaliableAmount\":100.0},\"detailURL\":\"<p style=\\\"text-align: center;\\\"><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/147/565/3280565741_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/741/475/3280574147_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/790/816/3280618097_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/841/475/3280574148_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/232/516/3280615232_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/222/949/3281949222_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/247/565/3280565742_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/332/516/3280615233_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/896/865/3280568698_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/790/259/3281952097_1600896868.jpg\\\" /></p>\"},{\"offerId\":536489059017,\"subject\":\"jv测试offer9\",\"offerUnit\":\"千克\",\"price\":{\"price\":12.0},\"imageList\":[\"http://product.1688nongchanping.com/offer/b356b09004d94f429f39c59c68768a38.jpg\",\"http://product.1688nongchanping.com/offer/b356b09004d94f429f39c59c68768a38.jpg\",\"http://product.1688nongchanping.com/offer/140-150302120045.jpg\"],\"featureList\":[],\"companyInfo\":null,\"saleInfo\":{\"saledCount\":null,\"avaliableAmount\":122.0},\"detailURL\":\"<div style=\\\"margin: 0px; padding: 0px;\\\">\\r\\n<p style=\\\"text-align: center;\\\"><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/147/565/3280565741_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/741/475/3280574147_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/790/816/3280618097_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/841/475/3280574148_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/232/516/3280615232_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/222/949/3281949222_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/247/565/3280565742_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/332/516/3280615233_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/896/865/3280568698_1600896868.jpg\\\" /><img style=\\\"visibility: visible;\\\" src=\\\"http://cbu01.alicdn.com/img/ibank/2016/790/259/3281952097_1600896868.jpg\\\" /></p>\\r\\n</div>\"},{\"offerId\":536489059001,\"subject\":\"正儿八经测试3\",\"offerUnit\":\"千克\",\"price\":{\"price\":12.0},\"imageList\":[\"http://product.1688nongchanping.com/offer/3132872979_999566913.jpg\",\"http://product.1688nongchanping.com/offer/3132872979_999566913.jpg\",\"http://product.1688nongchanping.com/offer/3214597083_919536840.jpg\"],\"featureList\":[],\"companyInfo\":null,\"saleInfo\":{\"saledCount\":null,\"avaliableAmount\":2323232.0},\"detailURL\":\"<p>&lt;p data-type=\\\"label-view\\\" style=\\\"color: rgb(255, 255, 255); font-size: 9px; height: 13px; margin-left: 15px; margin-top: 64px; width: 46px; background-image: url(&amp;quot;http://gtms02.alicdn.com/tps/i2/TB1dYb9KVXXXXX5XVXXjm1NHpXX-204-56.png&amp;quot;); background-size: contain; background-repeat: no-repeat;\\\" data-gravity=\\\"5\\\" roc-id=\\\"roc-13\\\"&gt;</p>\\r\\n<p>&nbsp; &nbsp; &lt;span class=\\\"label-content\\\" style=\\\"left: 0px; top: -2.5px;\\\"&gt;JV测试测试测试&lt;/span&gt;</p>\\r\\n<p>&lt;/p&gt;</p>\"},{\"offerId\":536449539162,\"subject\":\"正儿八经测试商品1\",\"offerUnit\":\"千克\",\"price\":{\"price\":23.0},\"imageList\":[\"http://product.1688nongchanping.com/offer/3211026576_999566913.jpg\",\"http://product.1688nongchanping.com/offer/3211026576_999566913.jpg\",\"http://product.1688nongchanping.com/offer/3132872979_999566913.jpg\"],\"featureList\":[],\"companyInfo\":null,\"saleInfo\":{\"saledCount\":null,\"avaliableAmount\":34567.0},\"detailURL\":\"<table>\\r\\n<tbody>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-comment\\\">&lt;!----&gt;</span><span class=\\\"html-doctype\\\">&lt;!DOCTYPE html&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;html&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;head&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;title&gt;</span>图文详情<span class=\\\"html-tag\\\">&lt;/title&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;meta <span class=\\\"html-attribute-name\\\">charset</span>=\\\"<span class=\\\"html-attribute-value\\\">gbk</span>\\\"&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;meta <span class=\\\"html-attribute-name\\\">name</span>=\\\"<span class=\\\"html-attribute-value\\\">data-spm</span>\\\" <span class=\\\"html-attribute-name\\\">content</span>=\\\"<span class=\\\"html-attribute-value\\\">a260g</span>\\\" /&gt;</span><span class=\\\"html-tag\\\">&lt;meta <span class=\\\"html-attribute-name\\\">name</span>='<span class=\\\"html-attribute-value\\\">date</span>' <span class=\\\"html-attribute-name\\\">content</span>='<span class=\\\"html-attribute-value\\\">1469761837251</span>'/&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;meta <span class=\\\"html-attribute-name\\\">name</span>=\\\"<span class=\\\"html-attribute-value\\\">viewport</span>\\\" <span class=\\\"html-attribute-name\\\">content</span>=\\\"<span class=\\\"html-attribute-value\\\">width=790px</span>\\\"&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;link <span class=\\\"html-attribute-name\\\">rel</span>=\\\"<span class=\\\"html-attribute-value\\\">stylesheet</span>\\\" <span class=\\\"html-attribute-name\\\">href</span>=\\\"<a class=\\\"html-attribute-value html-resource-link\\\" href=\\\"http://astyle.alicdn.com/fdevlib/css/lofty/port/lofty.css?_v=4900687.css\\\" target=\\\"_blank\\\">//astyle.alicdn.com/fdevlib/css/lofty/port/lofty.css?_v=4900687.css</a>\\\" /&gt;</span><span class=\\\"html-tag\\\">&lt;/link&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;script <span class=\\\"html-attribute-name\\\">type</span>=\\\"<span class=\\\"html-attribute-value\\\">text/javascript</span>\\\" <span class=\\\"html-attribute-name\\\">src</span>=\\\"<a class=\\\"html-attribute-value html-resource-link\\\" href=\\\"http://astyle.alicdn.com/m/lofty/port/lofty.js?_v=4900687.js\\\" target=\\\"_blank\\\">//astyle.alicdn.com/m/lofty/port/lofty.js?_v=4900687.js</a>\\\"&gt;</span><span class=\\\"html-tag\\\">&lt;/script&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;script <span class=\\\"html-attribute-name\\\">type</span>=\\\"<span class=\\\"html-attribute-value\\\">text/javascript</span>\\\" <span class=\\\"html-attribute-name\\\">src</span>=\\\"<a class=\\\"html-attribute-value html-resource-link\\\" href=\\\"http://astyle.alicdn.com/fdevlib/js/gallery/jquery/jquery-latest.js?_v=4900687.js\\\" target=\\\"_blank\\\">//astyle.alicdn.com/fdevlib/js/gallery/jquery/jquery-latest.js?_v=4900687.js</a>\\\"&gt;</span><span class=\\\"html-tag\\\">&lt;/script&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;style&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">div,p,td,a,strong,b,span{word-break:break-word}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">body img{</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">max-width:790px;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">vertical-align:bottom;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;/style&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;/head&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;body <span class=\\\"html-attribute-name\\\">data-spm</span>=\\\"<span class=\\\"html-attribute-value\\\">8029192</span>\\\"&gt;</span><span class=\\\"html-tag\\\">&lt;script <span class=\\\"html-attribute-name\\\">type</span>=<span class=\\\"html-attribute-value\\\">text/javascript</span>&gt;</span>var dmtrack_c='{-}'; var dmtrack_pageid='0ac6d5d80a6738c01470206317';</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">(function(d){var t=d.createElement('script');t.type='text/javascript';t.async=true;t.src='//astyle-src.alicdn.com/sys/js/beacon/cnb.js';d.getElementsByTagName('head')[0].appendChild(t);}(document));<span class=\\\"html-tag\\\">&lt;/script&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;noscript&gt;</span>&lt;img src=\\\"//dmtracking.1688.com/b.jpg?cD0yJnU9e3ZpZXcubS4xNjg4LmNvbSUyZmNtcyUyZm5hdGl2ZSUyZm9mZmVyZGV0YWlsJTJlaHRtbD91cmw9aHR0cCUzYSUyZiUyZmRzYyUyZXRhb2Jhb2NkbiUyZWNvbSUyZmk4JTJmNTMwJTJmMzgwJTJmNTM2MzgxODI4NjQ5JTJmVEIxRFpXb0xYWFhYWGJqWEZYWDhxdHBGWGxYJTJlZGVzYyUyNTdDdmFyJTI1NUVkZXNjJTI1M0JsYW5nJTI1NUVnYmslMjUzQnNpZ24lMjU1RTEwZDUwYzk3OTVmZmM0N2I3YmYwODhmZTAyZjExMzMzJTI1M0J0JTI1NUUxNDY5Njk3MDgzfSZtPXtHRVR9JnM9ezIwMH0mcj17LX0mYT17JTIyY19tcz0xfGNfbXQ9M3xjX21pZD1iMmItNjAyNDQ5Mjg4fGNfbGlkPW1yJTI1RTklMjVBMyUyNThFJTI1RTYlMjVCNSUyNTgxJTI1RTYlMjVCNiUyNTk1JTI1RTYlMjVCNyUyNThDJTIyfSZiPS0mYz17LX0K&amp;ver=40&amp;pageid=0ac6d5d80a6738c01470206317&amp;time=1470206317\\\" width=\\\"1\\\" height=\\\"1\\\" style=\\\"display:none\\\"&gt;<span class=\\\"html-tag\\\">&lt;/noscript&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;script <span class=\\\"html-attribute-name\\\">type</span>=<span class=\\\"html-attribute-value\\\">text/javascript</span>&gt;</span> var _SPM_a='{-}'; var _SPM_b='{-}';var _SPM_app_name='{-}';var _SPM_template_path='{-}';<span class=\\\"html-tag\\\">&lt;/script&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;script&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">with(document)with(body)with(insertBefore(createElement(\\\"script\\\"),firstChild))setAttribute(\\\"exparams\\\",\\\"category=&amp;userid=602449288&amp;aplus&amp;&amp;asid=AYil6CNtkaFXdONiEQAAAABPw8F55NX8kg==&amp;aat=%22c%5fms%3d1%7cc%5fmt%3d3%7cc%5fmid%3db2b%2d602449288%7cc%5flid%3dmr%25E9%25A3%258E%25E6%25B5%2581%25E6%25B6%2595%25E6%25B7%258C%22&amp;abi=42%2e120%2e74%2e159%2e1456797195765%2e338553%2e3&amp;abb=&amp;\\\",id=\\\"tb-beacon-aplus\\\",src=(location&gt;\\\"https\\\"?\\\"//g\\\":\\\"//g\\\")+\\\".alicdn.com/alilog/mlog/aplus_b2b.js\\\")</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;/script&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;/body&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;script <span class=\\\"html-attribute-name\\\">type</span>=\\\"<span class=\\\"html-attribute-value\\\">text/javascript</span>\\\"&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">define(['util/lazyload/1.0','jquery'],function(LazyLoad,J){</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var main={</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">init:function(){</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this.detailUrl =this._getUrlVars('url');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this.config = {},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this.container=J('body');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this._loadDesc();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_getUrlVars: function(name){</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var vars = [], hash;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&amp;');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">for(var i = 0; i &lt; hashes.length; i++){</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">hash = hashes[i].split('=');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">vars.push(hash[0]);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">vars[hash[0]] = hash[1];</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">return decodeURI(vars[name]);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_loadDesc: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (this.detailUrl) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this._initLazyLoadDescriptionTFS();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this._initLazyLoadDescription();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_initLazyLoadDescriptionTFS: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var that = this,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">descURLTFS = that.detailUrl;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">//新老地址处理</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (typeof(descURLTFS) === \\\"string\\\" &amp;&amp; descURLTFS.indexOf(\\\"/tfscom/\\\") &gt;= 0 &amp;&amp; descURLTFS.indexOf(\\\"?t=\\\") &lt; 0) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">descURLTFS = descURLTFS + '?t=' + new Date().getTime();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">J.ajax({</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">url: descURLTFS,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">dataType: 'script',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">timeout: 3000,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">cache: true,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">success: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (descURLTFS.indexOf(\\\"/tfscom/\\\") &gt;= 0) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (window.offer_details &amp;&amp; window.offer_details.content) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that._descriptionSuccessCallback(window.offer_details.content);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that._initLazyLoadDescription();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (window.desc) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that._descriptionSuccessCallback(window.desc);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that._initLazyLoadDescription();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">error: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that._initLazyLoadDescription();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_initLazyLoadDescription: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var that = this;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var descURL = that.detailUrl;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">//获取offer详情的数据</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">J.ajax(descURL, {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">dataType: 'jsonp',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">data: {},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">success: function(o) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (o.success === true) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that._descriptionSuccessCallback(o.offerDesc);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that.container.html('详情加载失败');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">error: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that.container.html('详情加载失败');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_descriptionSuccessCallback: function(o) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var self = this,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">heightStyle = '',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">widthStyle = '',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">styles='',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">imgRegx = /(&lt;img[^&gt;]*)(src *= *(\\\"[^\\\"]*\\\"|'[^']*'|[^ &gt;]*)) *[^&gt;]*&gt;/g,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">heightRegx = /(height[^:]*=\\\\s*(\\\"[^\\\"]*\\\"|'[^']*'|[^ &gt;]*))/g,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">widthRegx = /(width[^:]*=\\\\s*(\\\"[^\\\"]*\\\"|'[^']*'|[^ &gt;]*))/g,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">styleRegx =/style[^=]*=\\\\s*\\\"[^\\\"]*\\\"/g,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">html = '',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">imgCount, count = 0,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">imgs, tempEl,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">SPACEBALL = '//cbu01.alicdn.com/cms/upload/other/lazyload.png',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">that = this;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">html = o || '';</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">imgCount = html.match(imgRegx) ? html.match(imgRegx).length : 0;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">html = html.replace(imgRegx, function(m, p1, p2, p3) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">count++;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">//if (count &lt; 1) return m; // 前 1 个图片不处理</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (m.match(widthRegx)) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">widthStyle = m.match(widthRegx);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">widthStyle = '';</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if(m.match(styleRegx)){</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">styles = m.match(styleRegx);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}else{</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">styles = '';</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (m.indexOf('height') !== -1) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">heightStyle = m.match(heightRegx);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">heightStyle = '';</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (self.config.platform === 'iOS' &amp;&amp; (self.config.networkType === '2g' || self.config.networkType === '3g' || J(window).height() &lt; 481)) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">p3 = handleImgSize(p3, '450x5000', '200x200');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// } else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// p3 = handleImgSize(p3, '450x5000', '400x400');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">return [</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">'&lt;img ',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">'src=\\\"https:' + SPACEBALL + '\\\" data-lazyload-src=',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">p3.replace(/_\\\\.webp\\\"$/,'\\\"') + ' ',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">styles + ' ',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">widthStyle + ' ',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">heightStyle + ' &gt;'</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">].join('');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">/* ref: http://blog.stevenlevithan.com/archives/faster-than-innerhtml */</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this.container.html(html);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (this.container.html() === '' || this.container.html() == '&lt;p&gt;&lt;/p&gt;') {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this.container.html('卖家暂未添加产品描述');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this._initLink();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">imgs = J('img', this.container);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">for (var i = 0, l = imgs.length; i &lt; l; i++) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">//显示图片,一开始的时候图片都是隐藏的</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">imgs.eq(i).css('visibility', 'visible');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">//图片加载后缩放到detail页宽度</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">imgs.bind('load', function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">J(this).css('visibility', 'visible');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (this.width &gt; that.detailWidth &amp;&amp; J(this).closest('table').length === 0) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">J(this).width('100%');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">J(this).height('auto');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}).error(function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">J(this).hide();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this._initScroller();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">function handleImgSize(img, size, taobaoSize) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var p = img.match(/(\\\\S+)(\\\\.jpg'|\\\\.jpg\\\"|\\\\.jpg)((\\\\?)?(\\\\S+))J/),</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_img;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">&nbsp;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (img.search(/(\\\\d+)x(\\\\d+)\\\\.jpg/) == -1 &amp;&amp; img.search(/(\\\\.jpg'|\\\\.jpg\\\"|\\\\.jpg)J/) !== -1) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">if (img.indexOf('taobaocdn') !== -1 || img.indexOf('img.alicdn.com') !== -1) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// _img = p[1]+'.jpg_'+ taobaoSize + p[2];</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_img = img;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_img = p[1] + '.' + size + p[2]+p[3];</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">} else {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_img = img;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// var _img = img.replace(/(\\\\S+\\\\.jpg['\\\"]?)\\\\??[^\\\"']*([\\\"'])?J/, function(p, p1, p2) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// return p1 + (p2 || '');</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// });</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">return _img;</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_initLink: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">this.container.on('click', 'a', function(e) {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">e.preventDefault();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">/*var href = J(this).attr('href'),</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">result = href.match(/(\\\\d+)\\\\.html/);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">result[1] &amp;&amp; Wing.navigator.rewrite('URL', 'http://detail.m.1688.com/page/index.html?offerId=' + result[1]);*/</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">},</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">_initScroller: function() {</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// setTimeout(function(){</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// var myScroll = new Scroller({</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// container: '#d-content',</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// hScroll:true,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// vScroll:true,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// zoom: true,</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// checkDOMChanges: true</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// });</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">var lazy = new LazyLoad({</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">container: 'body'</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// scroller: myScroll</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">//lazy.init();</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">// }, 200);</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">}</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">};</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">J(function(){</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">main.init()</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\">});</td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;/script&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-tag\\\">&lt;/html&gt;</span></td>\\r\\n</tr>\\r\\n<tr>\\r\\n<td class=\\\"line-number\\\">&nbsp;</td>\\r\\n<td class=\\\"line-content\\\"><span class=\\\"html-comment\\\">&lt;!-- user defined footer --&gt;</span> <span class=\\\"html-end-of-file\\\"></span></td>\\r\\n</tr>\\r\\n</tbody>\\r\\n</table>\"}]");
-
-    data.put("c",resp);
-//    System.out.println("max long:"+Long.MAX_VALUE);
-    String result = WXJsonUtils.fromObjectToJSONString(data);
-    System.out.println(result);
-
-  }
-
-  static class TestObject{
-
-    private BigDecimal big = new BigDecimal(536649655068L);
-
-    public BigDecimal getBig() {
-      return big;
-    }
-
-    public void setBig(BigDecimal big) {
-      this.big = big;
-    }
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
deleted file mode 100644
index ece6e0e..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXEnvironment;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Created by sospartan on 9/18/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-@PrepareForTest({WXEnvironment.class})
-public class WXLogUtilsTest {
-  static class Log extends WXLogUtils{};
-
-  @Rule
-  public PowerMockRule rule = new PowerMockRule();
-
-  @Before
-  public void setUp() throws Exception {
-    WXLogUtils.isShowLineNumber = true;
-    PowerMockito.mockStatic(WXEnvironment.class);
-    PowerMockito.when(WXEnvironment.isApkDebugable()).thenReturn(true);
-  }
-
-  @Test
-  public void testD() throws Exception {
-    Log.d("test");
-    Log.d(null);
-    Log.d("tag","test");
-    Log.d("tag","test | __ | __ __DEBUG | __ ");
-    Log.d("tag",new Throwable("test"));
-  }
-
-  @Test
-  public void testI() throws Exception {
-    Log.i("test");
-    Log.i(null);
-    Log.i("tag","test");
-    Log.i("tag",new Throwable("test"));
-  }
-
-  @Test
-  public void testV() throws Exception {
-    Log.v("test");
-    Log.v(null);
-    Log.v("tag","test");
-    Log.v("tag",new Throwable("test"));
-  }
-
-  @Test
-  public void testW() throws Exception {
-    Log.w("test");
-    Log.w(null);
-    Log.w("tag","test");
-    Log.w("tag",new Throwable("test"));
-  }
-
-  @Test
-  public void testE() throws Exception {
-    Log.e("test");
-    Log.e(null);
-    Log.e("tag","test");
-    Log.e("tag",new Throwable("test"));
-  }
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/WXReflectionUtilsTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/WXReflectionUtilsTest.java
deleted file mode 100644
index 18df379..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXReflectionUtilsTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.taobao.weappplus_sdk.BuildConfig;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.Assert.*;
-
-/**
- * Created by sospartan on 8/2/16.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
-public class WXReflectionUtilsTest {
-
-  static class TestA{
-    private boolean value = false;
-  }
-
-  @Test
-  public void testParseArgument() throws Exception {
-   Object value =  WXReflectionUtils.parseArgument(String.class,"dkdkdkdk");
-    assertTrue(value instanceof String);
-
-    value = WXReflectionUtils.parseArgument(long.class,"123444");
-    assertTrue(value instanceof Long);
-
-    value = WXReflectionUtils.parseArgument(int.class,"123444");
-    assertTrue(value instanceof Integer);
-
-    value = WXReflectionUtils.parseArgument(Integer.class,"123444");
-    assertTrue(value instanceof Integer);
-
-    value = WXReflectionUtils.parseArgument(int.class,123444);
-    assertTrue(value instanceof Integer);
-
-    value = WXReflectionUtils.parseArgument(double.class, Double.toString(123.444d));
-    assertTrue(value instanceof Double);
-
-
-
-    JSONObject j = new JSONObject();
-    j.put("a","b");
-    j.put("c",23);
-    value = WXReflectionUtils.parseArgument(String.class,j);
-    assertTrue(value instanceof String);
-
-    value = WXReflectionUtils.parseArgument(Map.class,j);
-    assertTrue(value instanceof Map);
-    assertEquals(((Map)value).get("a"),"b");
-
-    value = WXReflectionUtils.parseArgument(JSONObject.class,j);
-    assertTrue(value instanceof JSONObject);
-    assertEquals(((JSONObject)value).get("a"),"b");
-    assertEquals(((JSONObject)value).get("c"),23);
-
-    value = WXReflectionUtils.parseArgument(JSONObject.class, JSON.toJSONString(j));
-    assertTrue(value instanceof JSONObject);
-    assertEquals(((JSONObject)value).get("a"),"b");
-    assertEquals(((JSONObject)value).get("c"),23);
-
-    JSONArray k = new JSONArray();
-    k.add("b");
-    k.add(23);
-    value = WXReflectionUtils.parseArgument(String[].class, k);
-    assertTrue(value instanceof String[]);
-    assertEquals(((String[])value)[0],"b");
-    assertEquals(((String[])value)[1],"23");
-
-    value = WXReflectionUtils.parseArgument(String[].class, JSON.toJSONString(k));
-    assertTrue(value instanceof String[]);
-    assertEquals(((String[])value)[0],"b");
-    assertEquals(((String[])value)[1],"23");
-
-    value = WXReflectionUtils.parseArgument(List.class, JSON.toJSONString(k));
-    assertTrue(value instanceof List);
-    assertEquals(((List)value).get(0),"b");
-    assertEquals(((List)value).get(1),23);
-
-    k = new JSONArray();
-    k.add(1);
-    k.add(23);
-    value = WXReflectionUtils.parseArgument(int[].class, JSON.toJSONString(k));
-    assertTrue(value instanceof int[]);
-    assertEquals(((int[])value)[0],1);
-    assertEquals(((int[])value)[1],23);
-  }
-
-  @Test
-  public void testSetValue() throws Exception {
-    TestA a = new TestA();
-
-    WXReflectionUtils.setValue(a,"value","true");
-    assertTrue(a.value);
-  }
-
-
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/WXResourceUtilsTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/WXResourceUtilsTest.java
deleted file mode 100644
index caaf8ab..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXResourceUtilsTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.graphics.Shader;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-/**
- * Created by caolijie on 16/8/4.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class WXResourceUtilsTest {
-
-  @Test
-  public void testColor1() throws Exception {
-    int color = WXResourceUtils.getColor("#ffffff");
-    assertEquals(color, 0xffffffff);
-
-    color = WXResourceUtils.getColor("#99ffffff");
-    assertEquals(color, 0x99ffffff);
-
-    color = WXResourceUtils.getColor("#aa123123");
-    assertEquals(color, 0xaa123123);
-
-    color = WXResourceUtils.getColor("#00000000");
-    assertEquals(color, 0x00000000);
-
-    //can't match
-    color = WXResourceUtils.getColor("#ssssss");
-    assertEquals(color, Integer.MIN_VALUE);
-  }
-
-  @Test
-  public void testColor2() throws Exception {
-    int color = WXResourceUtils.getColor("#123");
-    assertEquals(color, 0xff112233);
-
-    color = WXResourceUtils.getColor("#abc");
-    assertEquals(color, 0xffaabbcc);
-
-    //can't match
-    color = WXResourceUtils.getColor("#12332");
-    assertEquals(color, Integer.MIN_VALUE);
-
-    color = WXResourceUtils.getColor("#sss");
-    assertEquals(color, Integer.MIN_VALUE);
-  }
-
-  @Test
-  public void testColor3() throws Exception {
-    int color = WXResourceUtils.getColor("rgba(50%,50%,50%, 0.5)");
-    assertEquals(color, 0x7f7f7f7f);
-
-    color = WXResourceUtils.getColor("rgba( 50%, 50% , 50%   , 0.5 )");
-    assertEquals(color, 0x7f7f7f7f);
-
-    color = WXResourceUtils.getColor("rgba(255, 255, 255, 1.0)");
-    assertEquals(color, 0xffffffff);
-
-    color = WXResourceUtils.getColor("rgba(1%, 1% ,1%, 1)");
-    assertEquals(color, 0xff020202);
-
-    color = WXResourceUtils.getColor("rgba(0%, 0, 1%, 0.1)");
-    assertEquals(color, 0x19000002);
-
-    color = WXResourceUtils.getColor("rgba(100%, 100%, 100%, 0.1)");
-    assertEquals(color, 0x19ffffff);
-
-    color = WXResourceUtils.getColor("rgba(1, 1, 1, 1.0)");
-    assertEquals(color, 0xff010101);
-
-    //can't match
-    color = WXResourceUtils.getColor("rgba(0.1, 0.1, 0.1, 1.0)");
-    assertEquals(color, Integer.MIN_VALUE);
-
-    color = WXResourceUtils.getColor("rgba(10.0%, 101%, -0.1, 50%)");
-    assertEquals(color, Integer.MIN_VALUE);
-  }
-
-  @Test
-  public void testColor4() throws Exception {
-    int color = WXResourceUtils.getColor("rgb(255, 255, 255)");
-    assertEquals(color, 0xffffffff);
-
-    color = WXResourceUtils.getColor("rgb(000000, 255, 255)");
-    assertEquals(color, 0xff00ffff);
-
-    //can't match
-    color = WXResourceUtils.getColor("rgb(256, 256, 256)");
-    assertEquals(color, 0xffffffff);
-
-    color = WXResourceUtils.getColor("rgb(-1, 255, 255)");
-    assertEquals(color, 0xff00ffff);
-  }
-
-  @Test
-  public void testColor5() throws Exception {
-    int color = WXResourceUtils.getColor("aliceblue");
-    assertEquals(color, 0XFFF0F8FF);
-
-    color = WXResourceUtils.getColor("pink");
-    assertEquals(color, 0XFFFFC0CB);
-
-    //can't match
-    color = WXResourceUtils.getColor("jahskdja");
-    assertEquals(color, Integer.MIN_VALUE);
-  }
-
-  @Test
-  public void testGetShader() throws Exception {
-    Shader shader = WXResourceUtils.getShader("linear-gradient(to bottom,#a80077,blue)", 100, 100);
-    assertNotNull(shader);
-    shader = WXResourceUtils.getShader("linear-gradient(to bottom,#a80077,rgb(255,255,0))", 100, 100);
-    assertNotNull(shader);
-    shader = WXResourceUtils.getShader("linear-gradient(to bottom,#a80077,rgba(255,255,0,0.5))", 100, 100);
-    assertNotNull(shader);
-    shader = WXResourceUtils.getShader("gradient", 100, 100);
-    assertNull(shader);
-  }
-}
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/WXUtilsTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/WXUtilsTest.java
deleted file mode 100644
index e981c69..0000000
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXUtilsTest.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.taobao.weex.utils;
-
-import android.text.TextUtils;
-
-import com.taobao.weappplus_sdk.BuildConfig;
-import com.taobao.weex.WXEnvironment;
-import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.common.WXConfig;
-
-import junit.framework.TestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.robolectric.annotation.Config;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.mockito.Matchers.any;
-
-/**
- * Created by lixinke on 16/2/24.
- */
-@RunWith(PowerMockRunner.class)
-@Config(constants = BuildConfig.class, sdk = 19)
-@PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-@PrepareForTest( {WXEnvironment.class, WXViewUtils.class, WXSDKInstance.class, TextUtils.class})
-public class WXUtilsTest extends TestCase {
-
-    public static final float TEST_DENSITY = 3.0f;
-    public static final int TEST_SCREEN_WIDTH = 1024;
-    public static final int TEST_VIEW_PORT = 800;
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        Map<String, String> map = new HashMap<>();
-        map.put(WXConfig.scale, Float.toString(TEST_DENSITY));
-        PowerMockito.mockStatic(WXEnvironment.class);
-        PowerMockito.when(WXEnvironment.class, "getConfig").thenReturn(map);
-
-        PowerMockito.mockStatic(WXViewUtils.class);
-        PowerMockito.when(WXViewUtils.class, "getScreenWidth").thenReturn(TEST_SCREEN_WIDTH);
-
-        PowerMockito.mockStatic(WXSDKInstance.class);
-        PowerMockito.when(WXSDKInstance.class, "getViewPortWidth").thenReturn(TEST_VIEW_PORT);
-
-        PowerMockito.mockStatic(TextUtils.class);
-        PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer(new Answer<Boolean>() {
-            @Override
-            public Boolean answer(InvocationOnMock invocation) throws Throwable {
-                CharSequence a = (CharSequence) invocation.getArguments()[0];
-                return !(a != null && a.length() > 0);
-            }
-        });
-        // also look at @PrepareForTest if add mock of new class
-    }
-
-    @Test
-    public void testGetFloat() throws Exception {
-        float test_float = WXUtils.getFloat("12324.9px");
-        assertEquals(12324.9, test_float, 0.01);
-
-        assertEquals(WXUtils.fastGetFloat("1.2345",2), 1.23f);
-    }
-
-    @Test
-    public void testGetInt() throws Exception {
-        int test_int = WXUtils.getInt("23px");
-        assertEquals(23, test_int);
-    }
-
-    @Test
-    public void testGetLong() throws Exception {
-        long test_long = WXUtils.getLong("8098px");
-        assertEquals(8098, test_long);
-    }
-
-    @Test
-    public void testGetDouble() throws Exception {
-        double test_Double = WXUtils.getDouble("8098.8989px");
-        assertEquals(8098.8, test_Double, 0.1);
-    }
-
-    @Test
-    public void testGetFloatWX() throws Exception {
-        Float test_float = WXUtils.getFloatByViewport("100wx", TEST_VIEW_PORT);
-        Float want = 100 * TEST_DENSITY * TEST_VIEW_PORT / TEST_SCREEN_WIDTH;
-        assertEquals(test_float, want , 0.01);
-
-        test_float = WXUtils.getFloatByViewport("100px", TEST_VIEW_PORT);
-        want = 100F;
-        assertEquals(test_float, want);
-
-        test_float = WXUtils.getFloatByViewport("100.2", TEST_VIEW_PORT);
-        want = 100.2F;
-        assertEquals(test_float, want);
-
-        test_float = WXUtils.getFloatByViewport(100.2F, TEST_VIEW_PORT);
-        want = 100.2F;
-        assertEquals(test_float, want, 0.0001);
-
-        test_float = WXUtils.getFloatByViewport(100.2D, TEST_VIEW_PORT);
-        want = 100.2F;
-        assertEquals(test_float, want, 0.0001);
-
-        test_float = WXUtils.getFloatByViewport("NaN", TEST_VIEW_PORT);
-        want = Float.NaN;
-        assertEquals(test_float, want);
-    }
-
-    @Test
-    public void testGetIntWX() throws Exception {
-        Integer test_int = WXUtils.getInt("100wx");
-        Integer want = (int)(100 * TEST_DENSITY * 750 / TEST_SCREEN_WIDTH);
-        assertEquals(test_int, want);
-
-        test_int = WXUtils.getInt("100px");
-        want = 100;
-        assertEquals(test_int, want);
-
-        test_int = WXUtils.getInt("100");
-        want = 100;
-        assertEquals(test_int, want);
-
-        test_int = WXUtils.getInt(100);
-        want = 100;
-        assertEquals(test_int, want);
-
-        test_int = WXUtils.getInt(100.1);
-        want = 0;
-        assertEquals(test_int, want); // double can not cast to integer
-    }
-
-    @Test
-    public void testGetDoubleWX() throws Exception {
-        Double test_double = WXUtils.getDouble("100.32wx");
-        Double want = (100.32D * TEST_DENSITY * 750 / TEST_SCREEN_WIDTH);
-        assertEquals(test_double, want, 0.01);
-
-        test_double = WXUtils.getDouble("100px");
-        want = 100D;
-        assertEquals(test_double, want, 0.01);
-
-        test_double = WXUtils.getDouble("100");
-        want = 100D;
-        assertEquals(test_double, want, 0.01);
-
-        test_double = WXUtils.getDouble(100);
-        want = 100D;
-        assertEquals(test_double, want, 0.01);
-
-        test_double = WXUtils.getDouble(100.1);
-        want = 100.1D;
-        assertEquals(test_double, want, 0.01);
-    }
-
-}
diff --git a/android/sdk/src/test/java/org/mockito/configuration/MockitoConfiguration.java b/android/sdk/src/test/java/org/mockito/configuration/MockitoConfiguration.java
deleted file mode 100644
index d6f285c..0000000
--- a/android/sdk/src/test/java/org/mockito/configuration/MockitoConfiguration.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.mockito.configuration;
-
-/**
- * Created by sospartan on 7/28/16.
- */
-public class MockitoConfiguration extends DefaultMockitoConfiguration {
-  @Override
-  public boolean enableClassCache() {
-    return false;
-  }
-}
diff --git a/android/sdk/wrap.sh b/android/sdk/wrap.sh
index 2b0dfbe..0dc64d6 100644
--- a/android/sdk/wrap.sh
+++ b/android/sdk/wrap.sh
@@ -1,4 +1,20 @@
 #!/system/bin/sh
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
 HERE="$(cd "$(dirname "$0")" && pwd)"
 export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1,use_sigaltstack=0
 ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so)
diff --git a/android/settings.gradle b/android/settings.gradle
index 0cd6195..1baeb8d 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
 rootProject.name = 'weex-project'
 
 def updateSubmodule(){
@@ -8,7 +26,9 @@
     }
 }
 
-updateSubmodule()
+//if (new File('../.git').exists()) {
+//    updateSubmodule()
+//}
 
 include ":playground"
 project(":playground").projectDir=new File("../weex-playground/android/playground")
diff --git a/dangerfile-output.js b/dangerfile-output.js
index 3f58afe..9a5346a 100644
--- a/dangerfile-output.js
+++ b/dangerfile-output.js
@@ -40,20 +40,7 @@
   }
 }
 
-if (title === 'OCLint Result') {
-  const command = 'cat ios/sdk/oclint.log | grep -v "Summary: TotalFiles=" | grep -i "P[1|2]"'
-  const child = shell.exec(command)
-  if (child.stdout !== '') {
-    fail(child.stdout)
-    fail(title)
-  }
-  if (child.stderr !== '') {
-    fail(child.stderr)
-    fail(title)
-  }
-}
-else if (title === 'AndroidLint Result') {
-  var content = fs.readFileSync('android/sdk/build/reports/lint-results.html', 'utf8')
+function check_android_lint(content){
   // in xml report,Overview Section,Disabled Checks Section and Suppressing Warnings and Errors Section is not reported.
   // in html report, those Section are included,
   // but Overview Section can't work in markdown,
@@ -68,4 +55,23 @@
     fail(content)
     fail(title)
   }
+}
+
+if (title === 'OCLint Result') {
+  const command = 'cat ios/sdk/oclint.log | grep -v "Summary: TotalFiles=" | grep -i "P[1|2]"'
+  const child = shell.exec(command)
+  if (child.stdout !== '') {
+    fail(child.stdout)
+    fail(title)
+  }
+  if (child.stderr !== '') {
+    fail(child.stderr)
+    fail(title)
+  }
+}
+else if (title === 'AndroidLint Result') {
+  var apacheRelease_content = fs.readFileSync('android/sdk/build/reports/lint-results-apacheRelease.html', 'utf8')
+  var legacyRelease_content = fs.readFileSync('android/sdk/build/reports/lint-results-apacheRelease.html', 'utf8')
+  check_android_lint(apacheRelease_content)
+  check_android_lint(legacyRelease_content)
 }
\ No newline at end of file
diff --git a/dangerfile.js b/dangerfile.js
index 9f3cedd..8058c8e 100644
--- a/dangerfile.js
+++ b/dangerfile.js
@@ -292,6 +292,7 @@
   'test/js\-framework/case',
   'android/playground/app/src/main/assets',
   'android/sdk/assets',
+  'android/sdk/src/main/java/org/apache/weex/utils/WXDataStructureUtil.java',
   'ios/playground/bundlejs',
   'ios/sdk/WeexSDK/Resources',
   'ios/sdk/WeexSDK/Sources/Layout',
@@ -525,7 +526,6 @@
     message("According to the blame info, we recommended " + names.join(' , ') + " to be the reviewers.")
   }
 }
-message('danger test finished.')
 /*
  * find reviewer end
  */
diff --git a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
index feda1d7..8e2a0b1 100644
--- a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
+++ b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
@@ -618,6 +618,12 @@
 		D735F1B222D761F800B53CDF /* log_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D735F1AC22D761F800B53CDF /* log_utils.cpp */; };
 		D735F1B322D761F800B53CDF /* log_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D735F1AC22D761F800B53CDF /* log_utils.cpp */; };
 		D77286FF22C9B22C00E1DA7D /* eagle_bridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD9205FA223651D800EDF93D /* eagle_bridge.cpp */; };
+		D7D6B6E2238E1B1D00BE56DD /* WXDarkSchemeProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D6B6E1238E1B1D00BE56DD /* WXDarkSchemeProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D7D6B6E3238E1B1D00BE56DD /* WXDarkSchemeProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D6B6E1238E1B1D00BE56DD /* WXDarkSchemeProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D7D6B6E6238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D6B6E4238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m */; };
+		D7D6B6E7238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D6B6E4238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m */; };
+		D7D6B6E8238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D6B6E5238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h */; };
+		D7D6B6E9238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D6B6E5238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h */; };
 		DC03ADB91D508719003F76E7 /* WXTextAreaComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = DC03ADB71D508719003F76E7 /* WXTextAreaComponent.mm */; };
 		DC03ADBA1D508719003F76E7 /* WXTextAreaComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = DC03ADB81D508719003F76E7 /* WXTextAreaComponent.h */; };
 		DC15A3DB2010BC93009C8977 /* weex-main-jsfm.js in Resources */ = {isa = PBXBuildFile; fileRef = DC15A3D92010BC93009C8977 /* weex-main-jsfm.js */; };
@@ -1351,6 +1357,9 @@
 		D3FC0DF61C508B2A002B9E31 /* WXTimerModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTimerModule.m; sourceTree = "<group>"; };
 		D735F1AB22D761F800B53CDF /* log_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log_utils.h; sourceTree = "<group>"; };
 		D735F1AC22D761F800B53CDF /* log_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log_utils.cpp; sourceTree = "<group>"; };
+		D7D6B6E1238E1B1D00BE56DD /* WXDarkSchemeProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXDarkSchemeProtocol.h; sourceTree = "<group>"; };
+		D7D6B6E4238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXDarkSchemeDefaultImpl.m; sourceTree = "<group>"; };
+		D7D6B6E5238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXDarkSchemeDefaultImpl.h; sourceTree = "<group>"; };
 		DAB176F008F516E4F9391C61 /* libPods-WeexSDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WeexSDK.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		DC03ADB71D508719003F76E7 /* WXTextAreaComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXTextAreaComponent.mm; sourceTree = "<group>"; };
 		DC03ADB81D508719003F76E7 /* WXTextAreaComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXTextAreaComponent.h; sourceTree = "<group>"; };
@@ -1476,6 +1485,8 @@
 		59A583031CF5B2FD0081FD3E /* Handler */ = {
 			isa = PBXGroup;
 			children = (
+				D7D6B6E5238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h */,
+				D7D6B6E4238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m */,
 				33CE190C2153443000CF9670 /* WXJSFrameworkLoadDefaultImpl.h */,
 				33CE190D2153443000CF9670 /* WXJSFrameworkLoadDefaultImpl.m */,
 				59A583041CF5B2FD0081FD3E /* WXNavigationDefaultImpl.h */,
@@ -1857,6 +1868,7 @@
 		77D1611C1C02DD3C0010B15B /* Protocol */ = {
 			isa = PBXGroup;
 			children = (
+				D7D6B6E1238E1B1D00BE56DD /* WXDarkSchemeProtocol.h */,
 				33CE19122153444900CF9670 /* WXJSFrameworkLoadProtocol.h */,
 				17036A5220FDE7490029AE3D /* WXApmProtocol.h */,
 				17C74F0E2072147A00AB4CAB /* WXAnalyzerProtocol.h */,
@@ -2421,6 +2433,7 @@
 				BD88C13F22F02111004467AA /* render_action_remove_child_from_richtext.h in Headers */,
 				BD9205FB223651D900EDF93D /* eagle_bridge.h in Headers */,
 				BD9205F82236518700EDF93D /* WXDataRenderHandler.h in Headers */,
+				D7D6B6E2238E1B1D00BE56DD /* WXDarkSchemeProtocol.h in Headers */,
 				7715EB6221A69DD9001F1108 /* WXRichText.h in Headers */,
 				B8D66C1B21255730003960BD /* style.h in Headers */,
 				B8D66C2321255730003960BD /* layout.h in Headers */,
@@ -2443,6 +2456,7 @@
 				745ED2DA1C5F2C7E002DB5A8 /* WXView.h in Headers */,
 				B8F3323C2141A4C600701BA0 /* string_util.h in Headers */,
 				17B122252090AAB000387E33 /* WXSDKError.h in Headers */,
+				D7D6B6E8238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h in Headers */,
 				2AE5B7521CAB7DBD0082FDDB /* WXAComponent.h in Headers */,
 				B8D66C4521255730003960BD /* render_action_createbody.h in Headers */,
 				77D1614F1C02E3880010B15B /* WXUtility.h in Headers */,
@@ -2671,6 +2685,7 @@
 				B8D66C2621255730003960BD /* flex_enum.h in Headers */,
 				DCA445D21EFA594600D0CFA8 /* WXComponent+Display.h in Headers */,
 				DCA445A81EFA572B00D0CFA8 /* WXResourceResponse.h in Headers */,
+				D7D6B6E3238E1B1D00BE56DD /* WXDarkSchemeProtocol.h in Headers */,
 				DCA445BC1EFA57B000D0CFA8 /* WXConvert.h in Headers */,
 				B8D66C8021255730003960BD /* render_scroller_factory.h in Headers */,
 				DCA445C11EFA57D000D0CFA8 /* WXBridgeManager.h in Headers */,
@@ -2696,6 +2711,7 @@
 				B8D66C9221255730003960BD /* render_factory_interface.h in Headers */,
 				DCA445B41EFA577F00D0CFA8 /* WXJSExceptionProtocol.h in Headers */,
 				B8D66CA221255730003960BD /* WeexApiHeader.h in Headers */,
+				D7D6B6E9238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.h in Headers */,
 				74B81AEF1F73C3E900D3A61D /* WXComponent+DataBinding.h in Headers */,
 				DCA445B51EFA578400D0CFA8 /* WXJSExceptionInfo.h in Headers */,
 				B8D66C9E21255730003960BD /* json11.hpp in Headers */,
@@ -2997,8 +3013,7 @@
 					};
 					77D160FC1C02DBE70010B15B = {
 						CreatedOnToolsVersion = 7.1.1;
-						DevelopmentTeam = 5783442933;
-						ProvisioningStyle = Automatic;
+						ProvisioningStyle = Manual;
 					};
 					DCA445241EFA555400D0CFA8 = {
 						CreatedOnToolsVersion = 8.3.3;
@@ -3154,6 +3169,7 @@
 				747DF6831E31AEE4005C53A8 /* WXLength.m in Sources */,
 				17E5ACE2209211BD00EE81F1 /* WXTransition.mm in Sources */,
 				77E65A0E1C155E99008B8775 /* WXDivComponent.m in Sources */,
+				D7D6B6E6238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m in Sources */,
 				B8D66CAB21255730003960BD /* wson_util.cpp in Sources */,
 				ED053502207F4DEB007B4568 /* JSContext+Weex.m in Sources */,
 				2A60CE9D1C91733E00857B9F /* WXSwitchComponent.mm in Sources */,
@@ -3345,6 +3361,7 @@
 				B82A159920F857200098A509 /* WXSDKError.m in Sources */,
 				B82A159820F8556F0098A509 /* WXSDKInstance_performance.m in Sources */,
 				B82A159B20F857470098A509 /* WXWebSocketModule.m in Sources */,
+				D7D6B6E7238E1B2A00BE56DD /* WXDarkSchemeDefaultImpl.m in Sources */,
 				BA5F00F41FC6834C00F76B5C /* WXLocaleModule.m in Sources */,
 				DCA4452F1EFA55B300D0CFA8 /* WXResourceLoader.m in Sources */,
 				DCA445301EFA55B300D0CFA8 /* WXComponent+Events.m in Sources */,
@@ -3743,10 +3760,10 @@
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
-				CODE_SIGN_STYLE = Automatic;
+				CODE_SIGN_STYLE = Manual;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEFINES_MODULE = YES;
-				DEVELOPMENT_TEAM = 5783442933;
+				DEVELOPMENT_TEAM = "";
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
@@ -3785,6 +3802,7 @@
 				PRODUCT_BUNDLE_IDENTIFIER = com.taobao.WeexSDK;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
+				"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
 				SKIP_INSTALL = YES;
 				VALID_ARCHS = "arm64 armv7 x86_64 i386";
 				WARNING_CFLAGS = "";
@@ -3802,9 +3820,9 @@
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
-				CODE_SIGN_STYLE = Automatic;
+				CODE_SIGN_STYLE = Manual;
 				DEFINES_MODULE = YES;
-				DEVELOPMENT_TEAM = 5783442933;
+				DEVELOPMENT_TEAM = "";
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
@@ -3843,6 +3861,7 @@
 				PRODUCT_BUNDLE_IDENTIFIER = com.taobao.WeexSDK;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
+				"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
 				SKIP_INSTALL = YES;
 				VALID_ARCHS = "arm64 armv7 x86_64 i386";
 				WARNING_CFLAGS = "";
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
index 922986b..d72c379 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -145,12 +145,12 @@
     }];
     
     [_jsBridge registerCallUpdateComponentData:^NSInteger(NSString *instanceId, NSString *componentId, NSString *jsonData) {
-        if (_dataRenderHandler) {
+        if (weakSelf.dataRenderHandler) {
             WXPerformBlockOnComponentThread(^{
                 long start = [WXUtility getUnixFixTimeMillis];
                 WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId];
                 [instance.apmInstance addUpdateComponentDataTimestamp:start];
-                [_dataRenderHandler callUpdateComponentData:instanceId componentId:componentId jsonData:jsonData];
+                [weakSelf.dataRenderHandler callUpdateComponentData:instanceId componentId:componentId jsonData:jsonData];
                 [instance.apmInstance addUpdateComponentDataTime:[WXUtility getUnixFixTimeMillis] - start];
             });
         }
@@ -567,6 +567,7 @@
                         JSObjectSetPrototype(instanceContextRef, JSValueToObject(instanceContextRef, [instanceContextEnvironment valueForProperty:key].JSValueRef, NULL), JSObjectGetPrototype(instanceContextRef, instanceGlobalObject));
                     }
                     JSObjectSetProperty(instanceContextRef, instanceGlobalObject, propertyName, [instanceContextEnvironment valueForProperty:key].JSValueRef, 0, NULL);
+                    JSStringRelease(propertyName);
                 }
                 
                 if (WX_SYS_VERSION_LESS_THAN(@"10.2")) {
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
index e241609..f232ada 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
@@ -1302,6 +1302,7 @@
         _customPages[sId] = page;
     }
     
+    SetConvertCurrentPage(pageId);
     [WXCustomPageBridge parseRenderObject:data parentRef:"" index:0 genObject:^(const std::string &ref, const std::string &type, const std::string &parentRef, std::map<std::string, std::string> *styles, std::map<std::string, std::string> *attrs, std::set<std::string> *events, int index) {
         if (parentRef.empty()) {
             // is root body
@@ -1343,6 +1344,7 @@
 {
     RenderPageCustom* page = [self getPage:pageId];
     if (page && page->IsValid()) {
+        SetConvertCurrentPage(pageId);
         page->UpdateAttr([ref UTF8String] ?: "", [WXCustomPageBridge parseMapValuePairs:data]);
     }
 }
@@ -1351,6 +1353,7 @@
 {
     RenderPageCustom* page = [self getPage:pageId];
     if (page && page->IsValid()) {
+        SetConvertCurrentPage(pageId);
         page->UpdateStyle([ref UTF8String] ?: "", [WXCustomPageBridge parseMapValuePairs:data]);
     }
 }
@@ -1406,6 +1409,7 @@
         if (target && target->shouldHandleModuleMethod([moduleName UTF8String] ?: "", [methodName UTF8String] ?: "")) {
             __block const char* seralizedArguments = nullptr;
             __block const char* seralizedOptions = nullptr;
+            SetConvertCurrentPage(pageId);
             ConvertToCString(arguments, ^(const char * value) {
                 if (value != nullptr) {
                     seralizedArguments = strdup(value);
@@ -1495,6 +1499,7 @@
         if (target) {
             __block const char* seralizedArguments = nullptr;
             __block const char* seralizedOptions = nullptr;
+            SetConvertCurrentPage(pageId);
             ConvertToCString(arguments, ^(const char * value) {
                 if (value != nullptr) {
                     seralizedArguments = strdup(value);
@@ -1565,6 +1570,8 @@
         WeexCore::WeexCoreManager::Instance()->set_script_bridge(jsBridge);
         
         WeexCore::WeexCoreManager::Instance()->set_measure_function_adapter(new WeexCore::WXCoreMeasureFunctionBridge());
+
+        [[WXSDKManager bridgeMgr] checkJSThread];
     });
 }
 
@@ -1847,6 +1854,7 @@
         return;
     }
     
+    SetConvertCurrentPage(pageId);
     const std::string page([pageId UTF8String] ?: "");
     RenderManager::GetInstance()->CreatePage(page, [&] (RenderPage* pageInstance) -> RenderObject* {
         pageInstance->set_before_layout_needed(false); // we do not need before and after layout
@@ -1868,11 +1876,13 @@
 
 + (void)callUpdateAttrs:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data
 {
+    SetConvertCurrentPage(pageId);
     WeexCore::RenderManager::GetInstance()->UpdateAttr([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]);
 }
 
 + (void)callUpdateStyle:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data
 {
+    SetConvertCurrentPage(pageId);
     WeexCore::RenderManager::GetInstance()->UpdateStyle([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]);
 }
 
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm
index 9293fa5..0c3d251 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm
@@ -39,6 +39,7 @@
 #import "WXCoreBridge.h"
 #import "WXAnalyzerCenter.h"
 
+
 #import <dlfcn.h>
 
 #import <mach/mach.h>
@@ -80,6 +81,7 @@
 {
     _jsContext.instanceId = nil;
     __block JSContext* theContext = _jsContext;
+    _jsContext = nil; // Make sure that the context MUST be freed in JS thread.
     WXPerformBlockOnBridgeThreadForInstance(^{
          theContext = nil; // release the context in js thread to avoid main-thread deadlock
     }, _weexInstanceId);
@@ -142,7 +144,10 @@
 - (JSValue *)callJSMethod:(NSString *)method args:(NSArray *)args
 {
     WXLogDebug(@"Calling JS... method:%@, args:%@", method, args);
-//    __checkMutable(args);
+    WXPerformBlockOnMainThread(^{
+        [[WXBridgeManager sharedManager].lastMethodInfo setObject:method ?: @"" forKey:@"method"];
+        [[WXBridgeManager sharedManager].lastMethodInfo setObject:args ?: @[] forKey:@"args"];
+    });
     return [[_jsContext globalObject] invokeMethod:method withArguments:args];
 }
 
diff --git a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
index cfea370..2d26ff0 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
@@ -760,7 +760,7 @@
 
 - (WXJSExpression *)parsePrimaryExpression
 {
-    int type = _lookahead->type;
+    WXJSTokenType type = _lookahead->type;
     
     if (type == WXJSTokenTypePunctuator) {
         if (_lookahead->value == "[") {
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
index c58a796..dee6a8c 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
@@ -49,8 +49,12 @@
     /**
      *  View
      */
-    UIColor *_backgroundColor;
+    UIColor *_styleBackgroundColor;
+    UIColor *_darkSchemeBackgroundColor;
+    UIColor *_lightSchemeBackgroundColor;
     NSString *_backgroundImage;
+    NSString *_darkSchemeBackgroundImage;
+    NSString *_lightSchemeBackgroundImage;
     NSString *_clipRadius;
     WXClipType _clipToBounds;
     UIView *_view;
@@ -59,6 +63,8 @@
     WXBoxShadow *_originalBoxShadow;
     WXBoxShadow *_lastBoxShadow;
     WXBoxShadow *_boxShadow;
+    WXBoxShadow *_darkSchemeBoxShadow;
+    WXBoxShadow *_lightSchemeBoxShadow;
     
     /**
      * accessibility support
@@ -115,9 +121,17 @@
     WXThreadSafeCounter *_displayCounter;
     
     UIColor *_borderTopColor;
+    UIColor *_darkSchemeBorderTopColor;
+    UIColor *_lightSchemeBorderTopColor;
     UIColor *_borderRightColor;
+    UIColor *_darkSchemeBorderRightColor;
+    UIColor *_lightSchemeBorderRightColor;
     UIColor *_borderLeftColor;
+    UIColor *_darkSchemeBorderLeftColor;
+    UIColor *_lightSchemeBorderLeftColor;
     UIColor *_borderBottomColor;
+    UIColor *_darkSchemeBorderBottomColor;
+    UIColor *_lightSchemeBorderBottomColor;
     
     CGFloat _borderTopWidth;
     CGFloat _borderRightWidth;
@@ -170,11 +184,18 @@
     NSMutableDictionary<NSString *, NSArray *> *_eventParameters;
 }
 
-/* _transform may be modified in mutiple threads. DO NOT use "_transform = XXX" directly.
+/* DO NOT use "_transform = XXX" directly.
  Ivar access in ObjC is compiled to code with additional release or retain. So use Ivar in mutiple
  thread may lead to crash. Use an ATOMIC property is well enough. */
 @property (atomic, strong) WXTransform *transform;
 
+/**
+ DO NOT use "_backgroundColor" directly. The same reason as '_transform'.
+ */
+@property (atomic, strong) UIColor* styleBackgroundColor;
+@property (atomic, strong) UIColor* darkSchemeBackgroundColor;
+@property (atomic, strong) UIColor* lightSchemeBackgroundColor;
+
 ///--------------------------------------
 /// @name Package Internal Methods
 ///--------------------------------------
@@ -296,4 +317,6 @@
 
 - (BOOL)_isAffineTypeAs:(NSString *)type;
 
+- (WXBoxShadow*)_chooseBoxShadow;
+
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
index 865778c..5519de8 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
@@ -364,12 +364,24 @@
 }
 
 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
+    /* In this case, we forbid animation temporarily so that
+     setContentOffset in setCurrentIndex won't cause endless loop
+     on some devices.
+     We have to use _forbidSlideAnimation in setCurrentIndex because
+     sometimes JS will trigger the slider to slide to some posistion
+     with animation.
+     */
+    BOOL oldValue = _forbidSlideAnimation;
+    _forbidSlideAnimation = YES;
+    
     if (_infinite) {
         [self resetScrollView];
     } else {
         NSInteger index = _scrollView.contentOffset.x / self.width;
         [self setCurrentIndex:index];
     }
+        
+    _forbidSlideAnimation = oldValue;
 }
 
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
index 1cb8245..54700e0 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
@@ -53,14 +53,16 @@
 
 @interface WXImageComponent ()
 {
-    NSString * _imageSrc;
-    pthread_mutex_t _imageSrcMutex;
-    pthread_mutexattr_t _propertMutexAttr;
     BOOL _shouldUpdateImage;
     BOOL _mainImageSuccess;
 }
 
+@property (atomic, strong) NSString *src;
+@property (atomic, strong) NSString *darkSchemeSrc;
+@property (atomic, strong) NSString *lightSchemeSrc;
 @property (atomic, strong) NSString *placeholdSrc;
+@property (atomic, strong) NSString *darkSchemePlaceholderSrc;
+@property (atomic, strong) NSString *lightSchemePlaceholderSrc;
 @property (nonatomic, assign) CGFloat blurRadius;
 @property (nonatomic, assign) UIViewContentMode resizeMode;
 @property (nonatomic, assign) WXImageQuality imageQuality;
@@ -71,7 +73,7 @@
 @property (nonatomic) BOOL imageLoadEvent;
 @property (nonatomic) BOOL imageDownloadFinish;
 @property (nonatomic) BOOL downloadImageWithURL;
-@property (nonatomic ,strong) NSString* preUrl;
+@property (nonatomic, strong) NSString* preUrl;
 
 @end
 
@@ -88,17 +90,18 @@
             WXImageUpdateQueue = dispatch_queue_create("com.taobao.weex.ImageUpdateQueue", DISPATCH_QUEUE_SERIAL);
         }
         
-        pthread_mutexattr_init(&(_propertMutexAttr));
-        pthread_mutexattr_settype(&(_propertMutexAttr), PTHREAD_MUTEX_RECURSIVE);
-        pthread_mutex_init(&(_imageSrcMutex), &(_propertMutexAttr));
-        
         if (attributes[@"src"]) {
-             pthread_mutex_lock(&(_imageSrcMutex));
-            _imageSrc = [[WXConvert NSString:attributes[@"src"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
-             pthread_mutex_unlock(&(_imageSrcMutex));
+            self.src = [[WXConvert NSString:attributes[@"src"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
         } else {
             WXLogWarning(@"image src is nil");
         }
+        if (attributes[@"darkSchemeSrc"]) {
+            self.darkSchemeSrc = [[WXConvert NSString:attributes[@"darkSchemeSrc"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+        }
+        if (attributes[@"lightSchemeSrc"]) {
+            self.lightSchemeSrc = [[WXConvert NSString:attributes[@"lightSchemeSrc"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+        }
+        
         [self configPlaceHolder:attributes];
         
         NSString *resizeMode = attributes[@"resize"];
@@ -135,6 +138,12 @@
     if (attributes[@"placeHolder"] || attributes[@"placeholder"]) {
         self.placeholdSrc = [[WXConvert NSString:attributes[@"placeHolder"]?:attributes[@"placeholder"]]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
     }
+    if (attributes[@"darkSchemePlaceholder"]) {
+        self.darkSchemePlaceholderSrc = [[WXConvert NSString:attributes[@"darkSchemePlaceholder"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+    }
+    if (attributes[@"lightSchemePlaceholder"]) {
+        self.lightSchemePlaceholderSrc = [[WXConvert NSString:attributes[@"lightSchemePlaceholder"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+    }
 }
 
 - (void)configFilter:(NSDictionary *)styles needUpdate:(BOOL)needUpdate
@@ -258,12 +267,16 @@
 - (void)dealloc
 {
     [self cancelImage];
-    pthread_mutex_destroy(&(_imageSrcMutex));
-    pthread_mutexattr_destroy(&_propertMutexAttr);
 }
 
 - (void)updateAttributes:(NSDictionary *)attributes
 {
+    if (attributes[@"darkSchemeSrc"]) {
+        self.darkSchemeSrc = [[WXConvert NSString:attributes[@"darkSchemeSrc"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+    }
+    if (attributes[@"lightSchemeSrc"]) {
+        self.lightSchemeSrc = [[WXConvert NSString:attributes[@"lightSchemeSrc"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+    }
     if (attributes[@"src"]) {
         [self setImageSrc:[[WXConvert NSString:attributes[@"src"]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
     }
@@ -293,7 +306,17 @@
     [self _clipsToBounds];
     
     [self updateImage];
-    
+}
+
+- (void)schemeDidChange:(NSString*)scheme
+{
+    [super schemeDidChange:scheme];
+    if (_view) {
+        if (self.darkSchemeSrc || self.darkSchemePlaceholderSrc ||
+            self.lightSchemeSrc || self.lightSchemePlaceholderSrc) {
+            [self updateImage];
+        }
+    }
 }
 
 - (BOOL)_needsDrawBorder
@@ -358,26 +381,15 @@
     }
 }
 
-- (NSString *)imageSrc
-{
-    pthread_mutex_lock(&(_imageSrcMutex));
-    NSString * imageSrcCpy = [_imageSrc copy];
-    pthread_mutex_unlock(&(_imageSrcMutex));
-    
-    return imageSrcCpy;
-}
-
 - (void)setImageSrc:(NSString*)src
 {
-    if ([src isEqualToString:_imageSrc]) {
+    if ([src isEqualToString:self.src]) {
         // if image src is equal to then ignore it.
         return;
     }
-    pthread_mutex_lock(&(_imageSrcMutex));
-    _imageSrc = src;
+    self.src = src;
     _imageDownloadFinish = NO;
     ((UIImageView*)self.view).image = nil;
-    pthread_mutex_unlock(&(_imageSrcMutex));
     
     [self updateImage];
 }
@@ -391,20 +403,42 @@
     }
 }
 
+- (NSString*)chooseImage:(NSString*)src lightSrc:(NSString*)lightSrc darkSrc:(NSString*)darkSrc
+{
+    if ([self.weexInstance isDarkScheme]) {
+        if (darkSrc) {
+            return darkSrc;
+        }
+        else {
+            return src;
+        }
+    }
+    else if (lightSrc) {
+        return lightSrc;
+    }
+    else {
+        return src;
+    }
+}
+
 - (void)updateImage
 {
     if (CGSizeEqualToSize(_view.frame.size, CGSizeZero)) {
         _shouldUpdateImage = YES;
         return;
     }
+    
+    NSString* choosedSrc = [self chooseImage:self.src lightSrc:self.lightSchemeSrc darkSrc:self.darkSchemeSrc];
+    NSString* choosedPlaceholder = [self chooseImage:self.placeholdSrc lightSrc:self.lightSchemePlaceholderSrc darkSrc:self.darkSchemePlaceholderSrc];
+    
     __weak typeof(self) weakSelf = self;
     if (_downloadImageWithURL && [[self imageLoader] respondsToSelector:@selector(setImageViewWithURL:url:placeholderImage:options:progress:completed:)]) {
         _mainImageSuccess = NO;
         
         NSString *newURL = nil;
-        if (self.placeholdSrc) {
-            newURL = [self.placeholdSrc copy];
-            WX_REWRITE_URL([self placeholdSrc], WXResourceTypeImage, self.weexInstance)
+        if (choosedPlaceholder) {
+            newURL = [choosedPlaceholder copy];
+            WX_REWRITE_URL(choosedPlaceholder, WXResourceTypeImage, self.weexInstance)
             NSDictionary* extInfo = @{@"instanceId":[self _safeInstanceId], @"pageURL": self.weexInstance.scriptURL ?: @""};
             [[self imageLoader] setImageViewWithURL:(UIImageView*)self.view url:[NSURL URLWithString:newURL] placeholderImage:nil options:extInfo progress:nil completed:^(UIImage *image, NSError *error, WXImageLoaderCacheType cacheType, NSURL *imageURL) {
                 /* We cannot rely on image library even if we call setImage with placeholer before calling setImage with real url.
@@ -414,8 +448,8 @@
                     UIImageView *imageView = (UIImageView *)strongSelf.view;
                     if (imageView && imageView.image == image && strongSelf->_mainImageSuccess) {
                         // reload image with main image url
-                        NSString* newURL = [[strongSelf imageSrc] copy];
-                        WX_REWRITE_URL([strongSelf imageSrc], WXResourceTypeImage, strongSelf.weexInstance)
+                        NSString* newURL = [choosedSrc copy];
+                        WX_REWRITE_URL(choosedSrc, WXResourceTypeImage, strongSelf.weexInstance)
                         NSDictionary *userInfo = @{@"imageQuality":@(strongSelf.imageQuality), @"imageSharp":@(strongSelf.imageSharp),  @"blurRadius":@(strongSelf.blurRadius), @"instanceId":[strongSelf _safeInstanceId], @"pageURL": strongSelf.weexInstance.scriptURL ?: @""};
                         [[strongSelf imageLoader] setImageViewWithURL:imageView url:[NSURL URLWithString:newURL] placeholderImage:nil options:userInfo progress:nil completed:^(UIImage *image, NSError *error, WXImageLoaderCacheType cacheType, NSURL *imageURL) {
                             WXLogInfo(@"Image re-requested because placeholder may override main image. %@", imageURL);
@@ -424,11 +458,11 @@
                 }
             }];
         }
-        newURL = [[self imageSrc] copy];
+        newURL = [choosedSrc copy];
         if ([newURL length] == 0) {
             return;
         }
-        WX_REWRITE_URL([self imageSrc], WXResourceTypeImage, self.weexInstance)
+        WX_REWRITE_URL(choosedSrc, WXResourceTypeImage, self.weexInstance)
         NSDictionary *userInfo = @{@"imageQuality":@(self.imageQuality), @"imageSharp":@(self.imageSharp),  @"blurRadius":@(self.blurRadius), @"instanceId":[self _safeInstanceId], @"pageURL": self.weexInstance.scriptURL ?: @""};
         [[self imageLoader] setImageViewWithURL:(UIImageView*)self.view url:[NSURL URLWithString:newURL] placeholderImage:nil options:userInfo progress:^(NSInteger receivedSize, NSInteger expectedSize) {
             // progress when loading image
@@ -444,9 +478,9 @@
                 WXLogError(@"Error downloading image: %@, detail:%@", imageURL.absoluteString, [error localizedDescription]);
                 
                 // retry set placeholder, maybe placeholer image can be downloaded
-                if (strongSelf.placeholdSrc) {
-                    NSString *newURL = [strongSelf.placeholdSrc copy];
-                    WX_REWRITE_URL([strongSelf placeholdSrc], WXResourceTypeImage, strongSelf.weexInstance)
+                if (choosedPlaceholder) {
+                    NSString *newURL = [choosedPlaceholder copy];
+                    WX_REWRITE_URL(choosedPlaceholder, WXResourceTypeImage, strongSelf.weexInstance)
                     [[strongSelf imageLoader] setImageViewWithURL:(UIImageView*)strongSelf.view
                                                               url:[NSURL URLWithString:newURL]
                                                  placeholderImage:nil
@@ -513,7 +547,7 @@
             [strongSelf updatePlaceHolderWithFailedBlock:downloadFailed];
             [strongSelf updateContentImageWithFailedBlock:downloadFailed];
 
-            if (!strongSelf.imageSrc && !strongSelf.placeholdSrc) {
+            if (!choosedSrc && !choosedPlaceholder) {
                 dispatch_async(dispatch_get_main_queue(), ^{
                     strongSelf.layer.contents = nil;
                     strongSelf.imageDownloadFinish = YES;
@@ -526,15 +560,15 @@
 
 - (void)updatePlaceHolderWithFailedBlock:(void(^)(NSString *, NSError *))downloadFailedBlock
 {
-    NSString *placeholderSrc = self.placeholdSrc;
+    NSString* choosedPlaceholder = [self chooseImage:self.placeholdSrc lightSrc:self.lightSchemePlaceholderSrc darkSrc:self.darkSchemePlaceholderSrc];
     
-    if ([WXUtility isBlankString:placeholderSrc]) {
+    if ([WXUtility isBlankString:choosedPlaceholder]) {
         return;
     }
     
-    WXLogDebug(@"Updating image, component:%@, placeholder:%@ ", self.ref, placeholderSrc);
-    NSString *newURL = [self.placeholdSrc copy];
-    WX_REWRITE_URL(self.placeholdSrc, WXResourceTypeImage, self.weexInstance)
+    WXLogDebug(@"Updating image, component:%@, placeholder:%@ ", self.ref, choosedPlaceholder);
+    NSString *newURL = [choosedPlaceholder copy];
+    WX_REWRITE_URL(choosedPlaceholder, WXResourceTypeImage, self.weexInstance)
     
     __weak typeof(self) weakSelf = self;
     self.placeholderOperation = [[self imageLoader] downloadImageWithURL:newURL imageFrame:self.calculatedFrame
@@ -543,16 +577,21 @@
     {
         dispatch_async(dispatch_get_main_queue(), ^{
             __strong typeof(self) strongSelf = weakSelf;
+            if (strongSelf == nil) {
+                return;
+            }
             UIImage *viewImage = ((UIImageView *)strongSelf.view).image;
             if (error) {
-                downloadFailedBlock(placeholderSrc,error);
+                downloadFailedBlock(choosedPlaceholder, error);
                 if ([strongSelf isViewLoaded] && !viewImage) {
                     ((UIImageView *)(strongSelf.view)).image = nil;
                     [strongSelf readyToRender];
                 }
                 return;
             }
-            if (![placeholderSrc isEqualToString:strongSelf.placeholdSrc]) {
+            
+            NSString* currentPlaceholder = [strongSelf chooseImage:strongSelf.placeholdSrc lightSrc:strongSelf.lightSchemePlaceholderSrc darkSrc:strongSelf.darkSchemePlaceholderSrc];
+            if (![choosedPlaceholder isEqualToString:currentPlaceholder]) {
                 return;
             }
             
@@ -570,20 +609,24 @@
 
 - (void)updateContentImageWithFailedBlock:(void(^)(NSString *, NSError *))downloadFailedBlock
 {
-    NSString *imageSrc = [NSString stringWithFormat:@"%@", self.imageSrc?:@""];
-    if ([WXUtility isBlankString:imageSrc]) {
+    NSString* choosedSrc = [self chooseImage:self.src lightSrc:self.lightSchemeSrc darkSrc:self.darkSchemeSrc];
+    
+    if ([WXUtility isBlankString:choosedSrc]) {
         WXLogError(@"image src is empty");
         return;
     }
     
-    WXLogDebug(@"Updating image:%@, component:%@", self.imageSrc, self.ref);
+    WXLogDebug(@"Updating image:%@, component:%@", choosedSrc, self.ref);
     NSDictionary *userInfo = @{@"imageQuality":@(self.imageQuality), @"imageSharp":@(self.imageSharp), @"blurRadius":@(self.blurRadius), @"instanceId":[self _safeInstanceId], @"pageURL": self.weexInstance.scriptURL ?: @""};
-    NSString * newURL = [imageSrc copy];
-    WX_REWRITE_URL(imageSrc, WXResourceTypeImage, self.weexInstance)
+    NSString * newURL = [choosedSrc copy];
+    WX_REWRITE_URL(choosedSrc, WXResourceTypeImage, self.weexInstance)
     __weak typeof(self) weakSelf = self;
     weakSelf.imageOperation = [[weakSelf imageLoader] downloadImageWithURL:newURL imageFrame:weakSelf.calculatedFrame userInfo:userInfo completed:^(UIImage *image, NSError *error, BOOL finished) {
         dispatch_async(dispatch_get_main_queue(), ^{
             __strong typeof(self) strongSelf = weakSelf;
+            if (strongSelf == nil) {
+                return;
+            }
             
             if (strongSelf.imageLoadEvent) {
                 NSMutableDictionary *sizeDict = [NSMutableDictionary new];
@@ -598,12 +641,13 @@
                 [strongSelf fireEvent:@"load" params:@{ @"success": error? @false : @true,@"size":sizeDict}];
             }
             if (error) {
-                downloadFailedBlock(imageSrc, error);
+                downloadFailedBlock(choosedSrc, error);
                 [strongSelf readyToRender];
                 return ;
             }
             
-            if (![imageSrc isEqualToString:strongSelf.imageSrc]) {
+            NSString* currentSrc = [strongSelf chooseImage:strongSelf.src lightSrc:strongSelf.lightSchemeSrc darkSrc:strongSelf.darkSchemeSrc];
+            if (![choosedSrc isEqualToString:currentSrc]) {
                 return ;
             }
             
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXRichText.mm b/ios/sdk/WeexSDK/Sources/Component/WXRichText.mm
index 8ffeaf3..341c2a7 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXRichText.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXRichText.mm
@@ -27,6 +27,7 @@
 #import "WXImgLoaderProtocol.h"
 #import "WXComponentManager.h"
 #import "WXLog.h"
+#import "WXDarkSchemeProtocol.h"
 #include <pthread/pthread.h>
 
 @interface WXRichNode : NSObject
@@ -35,7 +36,11 @@
 @property (nonatomic, strong) NSString  *ref;
 @property (nonatomic, strong) NSString  *text;
 @property (nonatomic, strong) UIColor   *color;
+@property (nonatomic, strong) UIColor   *darkSchemeColor;
+@property (nonatomic, strong) UIColor   *lightSchemeColor;
 @property (nonatomic, strong) UIColor   *backgroundColor;
+@property (nonatomic, strong) UIColor   *darkSchemeBackgroundColor;
+@property (nonatomic, strong) UIColor   *lightSchemeBackgroundColor;
 @property (nonatomic, strong) NSString  *fontFamily;
 @property (nonatomic, assign) CGFloat   fontSize;
 @property (nonatomic, assign) CGFloat   fontWeight;
@@ -91,7 +96,9 @@
     id value = styles[@#key]; \
     if (value) { \
         node.key = [WXConvert type:value];\
-    } else if (!([@#key isEqualToString:@"backgroundColor"] || [@#key isEqualToString:@"textDecoration"]) && superNode.key ) { \
+    } else if (!([@#key isEqualToString:@"backgroundColor"] || \
+        [@#key isEqualToString:@"weexDarkSchemeBackgroundColor"] || \
+        [@#key isEqualToString:@"textDecoration"]) && superNode.key ) { \
         node.key = superNode.key; \
     } \
 } while(0);
@@ -190,7 +197,11 @@
 - (void)fillCSSStyles:(NSDictionary *)styles toNode:(WXRichNode *)node superNode:(WXRichNode *)superNode
 {
     WX_STYLE_FILL_RICHTEXT(color, UIColor)
+    WX_STYLE_FILL_RICHTEXT(darkSchemeColor, UIColor)
+    WX_STYLE_FILL_RICHTEXT(lightSchemeColor, UIColor)
     WX_STYLE_FILL_RICHTEXT(backgroundColor, UIColor)
+    WX_STYLE_FILL_RICHTEXT(darkSchemeBackgroundColor, UIColor)
+    WX_STYLE_FILL_RICHTEXT(lightSchemeBackgroundColor, UIColor)
     WX_STYLE_FILL_RICHTEXT(fontFamily, NSString)
     WX_STYLE_FILL_RICHTEXT_PIXEL(fontSize)
     WX_STYLE_FILL_RICHTEXT(fontWeight, WXTextWeight)
@@ -421,6 +432,20 @@
     };
 }
 
+- (void)schemeDidChange:(NSString*)scheme
+{
+    [super schemeDidChange:scheme];
+    if ([self isViewLoaded]) {
+        // Force inner layout
+        [self innerLayout];
+    }
+}
+
+- (WXColorScene)colorSceneType
+{
+    return WXColorSceneText;
+}
+
 #pragma mark Text Building
 
 - (NSMutableAttributedString *)buildAttributeString
@@ -434,6 +459,16 @@
     NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] init];
     NSUInteger location;
     
+    BOOL invert = self.invertForDarkScheme;
+    
+    // Invert default background color.
+    UIColor* defaultTextColor = [UIColor blackColor];
+    UIColor* defaultBackgroundColor = _backgroundColor;
+    if (invert && [self.weexInstance isDarkScheme]) {
+        defaultTextColor = [[WXSDKInstance darkSchemeColorHandler] getInvertedColorFor:[UIColor blackColor] ofScene:[self colorSceneType] withDefault:[UIColor blackColor]];
+        defaultBackgroundColor = [[WXSDKInstance darkSchemeColorHandler] getInvertedColorFor:_backgroundColor ofScene:[self colorSceneType] withDefault:_backgroundColor];
+    }
+    
     __weak typeof(self) weakSelf = self;
     for (WXRichNode *node in array) {
         location = attrStr.length;
@@ -444,8 +479,10 @@
                 [attrStr.mutableString appendString:text];
                 
                 NSRange range = NSMakeRange(location, text.length);
-                [attrStr addAttribute:NSForegroundColorAttributeName value:node.color ?: [UIColor blackColor] range:range];
-                [attrStr addAttribute:NSBackgroundColorAttributeName value:node.backgroundColor ?: _backgroundColor range:range];
+                UIColor* textColor = [self.weexInstance chooseColor:node.color lightSchemeColor:node.lightSchemeColor darkSchemeColor:node.darkSchemeColor invert:invert scene:[self colorSceneType]];
+                UIColor* bgColor = [self.weexInstance chooseColor:node.backgroundColor lightSchemeColor:node.lightSchemeBackgroundColor darkSchemeColor:node.darkSchemeBackgroundColor invert:invert scene:[self colorSceneType]];
+                [attrStr addAttribute:NSForegroundColorAttributeName value:textColor ?: defaultTextColor range:range];
+                [attrStr addAttribute:NSBackgroundColorAttributeName value:bgColor ?: defaultBackgroundColor range:range];
                 
                 UIFont *font = [WXUtility fontWithSize:node.fontSize textWeight:node.fontWeight textStyle:WXTextStyleNormal fontFamily:node.fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
                 if (font) {
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
index 4d3f4c9..981a7af 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
@@ -1152,6 +1152,11 @@
             _flexCssNode->calculateLayout(renderPageSize);
             _flexCssNode->setParent(parent, _flexCssNode);
             
+            /* We must clear BFCs becuase we have set parent of _flexCSSNode to nullptr and
+             manually called its calculateLayout method. This will cause a non-bfc layout node
+             to have items in its BFCs vector. Later, a wild pointer may cause crash. */
+            _flexCssNode->clearBFCs();
+            
             // set origin and size back
             _flexCssNode->rewriteLayoutResult(left, top, width, height);
         }
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
index a796b49..c937680 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
@@ -119,7 +119,10 @@
 static CGFloat WXTextDefaultLineThroughWidth = 1.2;
 
 @interface WXTextComponent()
-@property (nonatomic, strong) NSString *useCoreTextAttr;
+@property (atomic, strong) NSString *fontFamily;
+@property (atomic, strong) UIColor *textColor;
+@property (atomic, strong) UIColor *darkSchemeTextColor;
+@property (atomic, strong) UIColor *lightSchemeTextColor;
 @end
 
 @implementation WXTextComponent
@@ -128,8 +131,6 @@
     UIEdgeInsets _padding;
     NSTextStorage *_textStorage;
     float _textStorageWidth;
-    float _color[4];
-    NSString *_fontFamily;
     float _fontSize;
     float _fontWeight;
     WXTextStyle _fontStyle;
@@ -150,6 +151,8 @@
     pthread_mutexattr_t _propertMutexAttr;
     BOOL _observerIconfont;
     BOOL _enableCopy;
+    
+    BOOL _useCoreText;
 }
 
 - (instancetype)initWithRef:(NSString *)ref
@@ -169,12 +172,10 @@
         _textAlign = NSTextAlignmentNatural;
         
         if ([attributes objectForKey:@"coretext"]) {
-            _useCoreTextAttr = [WXConvert NSString:attributes[@"coretext"]];
+            _useCoreText = [WXConvert BOOL:attributes[@"coretext"]];
         } else {
-            _useCoreTextAttr = nil;
+            _useCoreText = YES;
         }
-        
-        _color[0] = -1.0;
 
         [self fillCSSStyles:styles];
         [self fillAttributes:attributes];
@@ -185,18 +186,12 @@
 
 - (BOOL)useCoreText
 {
-    if ([_useCoreTextAttr isEqualToString:@"true"]) {
-        return YES;
-    }
-    if ([_useCoreTextAttr isEqualToString:@"false"]) {
-        return NO;
-    }
-    return YES;
+    return _useCoreText;
 }
 
 - (void)dealloc
 {
-    if (_fontFamily && _observerIconfont) {
+    if (self.fontFamily && _observerIconfont) {
         [[NSNotificationCenter defaultCenter] removeObserver:self name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
     }
     pthread_mutex_destroy(&_ctAttributedStringMutex);
@@ -246,7 +241,15 @@
 
 - (void)fillCSSStyles:(NSDictionary *)styles
 {
-    WX_STYLE_FILL_TEXT(fontFamily, fontFamily, NSString, YES) //!OCLint
+    do {
+        id value = styles[@"fontFamily"];
+        if (value) {
+            self.fontFamily = [WXConvert NSString:value];
+            [self setNeedsRepaint];
+            [self setNeedsLayout];
+        }
+    } while(0);
+    
     WX_STYLE_FILL_TEXT_PIXEL(fontSize, fontSize, YES) //!OCLint
     WX_STYLE_FILL_TEXT(fontWeight, fontWeight, WXTextWeight, YES) //!OCLint
     WX_STYLE_FILL_TEXT(fontStyle, fontStyle, WXTextStyle, YES) //!OCLint
@@ -258,26 +261,58 @@
     WX_STYLE_FILL_TEXT_PIXEL(letterSpacing, letterSpacing, YES) //!OCLint
     WX_STYLE_FILL_TEXT(wordWrap, wordWrap, NSString, YES); //!OCLint
 
-    UIColor* color = nil;
-    id value = styles[@"color"];
-    if (value) {
-        if([WXUtility isBlankString:value]){
-            color = [UIColor blackColor];
-        } else {
-            color = [WXConvert UIColor:value];
+    do {
+        UIColor* color = nil;
+        id value = styles[@"color"];
+        if (value) {
+            if([WXUtility isBlankString:value]){
+                color = [UIColor blackColor];
+            } else {
+                color = [WXConvert UIColor:value];
+            }
+            if (color) {
+                self.textColor = color;
+                [self setNeedsRepaint];
+            }
         }
-        if (color) {
-            [self setNeedsRepaint];
-            CGFloat red, green, blue, alpha;
-            [color getRed:&red green:&green blue:&blue alpha:&alpha];
-            _color[0] = red;
-            _color[1] = green;
-            _color[2] = blue;
-            _color[3] = alpha;
+        if (self.textColor == nil) {
+            self.textColor = [UIColor blackColor];
         }
-    }
+    } while (0);
 
-    if (_fontFamily && !_observerIconfont) {
+    do {
+        UIColor* color = nil;
+        id value = styles[@"weexDarkSchemeColor"];
+        if (value) {
+            if([WXUtility isBlankString:value]){
+                color = [UIColor blackColor];
+            } else {
+                color = [WXConvert UIColor:value];
+            }
+            if (color) {
+                self.darkSchemeTextColor = color;
+                [self setNeedsRepaint];
+            }
+        }
+    } while (0);
+    
+    do {
+        UIColor* color = nil;
+        id value = styles[@"weexLightSchemeColor"];
+        if (value) {
+            if([WXUtility isBlankString:value]){
+                color = [UIColor blackColor];
+            } else {
+                color = [WXConvert UIColor:value];
+            }
+            if (color) {
+                self.lightSchemeTextColor = color;
+                [self setNeedsRepaint];
+            }
+        }
+    } while (0);
+    
+    if (self.fontFamily && !_observerIconfont) {
         // notification received when custom icon font file download finish
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(repaintText:) name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
         _observerIconfont = YES;
@@ -368,6 +403,20 @@
     [self setNeedsRepaint];
 }
 
+- (void)schemeDidChange:(NSString*)scheme
+{
+    [self setNeedsRepaint];
+    [super schemeDidChange:scheme];
+    if (_view) {
+        [self setNeedsDisplay];
+    }
+}
+
+- (WXColorScene)colorSceneType
+{
+    return WXColorSceneText;
+}
+
 - (BOOL)needsDrawRect
 {
     return YES;
@@ -473,7 +522,7 @@
 
 - (void)repaintText:(NSNotification *)notification
 {
-    if (![_fontFamily isEqualToString:notification.userInfo[@"fontFamily"]]) {
+    if (![self.fontFamily isEqualToString:notification.userInfo[@"fontFamily"]]) {
         return;
     }
     [self setNeedsRepaint];
@@ -494,19 +543,20 @@
         string = @"";
     }
     NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString: string];
-    if (_color[0] >= 0) {
-        [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:_color[0] green:_color[1] blue:_color[2] alpha:_color[3]] range:NSMakeRange(0, string.length)];
+    UIColor* textColor = [self.weexInstance chooseColor:self.textColor lightSchemeColor:self.lightSchemeTextColor darkSchemeColor:self.darkSchemeTextColor invert:self.invertForDarkScheme scene:[self colorSceneType]];
+    if (textColor) {
+        [attributedString addAttribute:NSForegroundColorAttributeName value:textColor range:NSMakeRange(0, string.length)];
     }
     
     // set font
-    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:WXTextStyleNormal fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor useCoreText:[self useCoreText]];
+    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:WXTextStyleNormal fontFamily:self.fontFamily scaleFactor:self.weexInstance.pixelScaleFactor useCoreText:[self useCoreText]];
     CTFontRef ctFont;
     
     if (_fontStyle == WXTextStyleItalic) {
         CGAffineTransform matrix = CGAffineTransformMake(1, 0, tanf(16 * (CGFloat)M_PI / 180), 1, 0, 0);
-        ctFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName, font.pointSize, &matrix);
+        ctFont = CTFontCreateWithFontDescriptor((__bridge CTFontDescriptorRef)font.fontDescriptor, font.pointSize, &matrix);
     }else {
-        ctFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName, font.pointSize, NULL);
+        ctFont = CTFontCreateWithFontDescriptor((__bridge CTFontDescriptorRef)font.fontDescriptor, font.pointSize, NULL);
     }
     
     _fontAscender = font.ascender;
@@ -582,12 +632,13 @@
     NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
     
     // set textColor
-    if (_color[0] >= 0) {
-        [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:_color[0] green:_color[1] blue:_color[2] alpha:_color[3]] range:NSMakeRange(0, string.length)];
+    UIColor* textColor = [self.weexInstance chooseColor:self.textColor lightSchemeColor:self.lightSchemeTextColor darkSchemeColor:self.darkSchemeTextColor invert:self.invertForDarkScheme scene:[self colorSceneType]];
+    if (textColor) {
+        [attributedString addAttribute:NSForegroundColorAttributeName value:textColor range:NSMakeRange(0, string.length)];
     }
     
     // set font
-    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
+    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:self.fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
     if (font) {
         [attributedString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, string.length)];
     }
@@ -898,7 +949,7 @@
         CGFloat fontSize = font ? CTFontGetSize(font):32 * self.weexInstance.pixelScaleFactor;
         UIFont * uiFont = [UIFont systemFontOfSize:fontSize];
         if (uiFont) {
-            font = CTFontCreateWithName((__bridge CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
+            font = CTFontCreateWithFontDescriptor((__bridge CTFontDescriptorRef)uiFont.fontDescriptor, uiFont.pointSize, NULL);
         }
         if (font) {
             attrs[(id)kCTFontAttributeName] = (__bridge id)(font);
@@ -1109,10 +1160,15 @@
 {
     [super _resetCSSNodeStyles:styles];
     if ([styles containsObject:@"color"]) {
-        _color[0] = 0;
-        _color[1] = 0;
-        _color[2] = 0;
-        _color[3] = 1.0;
+        self.textColor = [UIColor blackColor];
+        [self setNeedsRepaint];
+    }
+    if ([styles containsObject:@"weexDarkSchemeColor"]) {
+        self.darkSchemeTextColor = nil;
+        [self setNeedsRepaint];
+    }
+    if ([styles containsObject:@"weexLightSchemeColor"]) {
+        self.lightSchemeTextColor = nil;
         [self setNeedsRepaint];
     }
     if ([styles containsObject:@"fontSize"]) {
diff --git a/ios/sdk/WeexSDK/Sources/Display/WXComponent+Display.m b/ios/sdk/WeexSDK/Sources/Display/WXComponent+Display.m
index 9acb010..2251731 100644
--- a/ios/sdk/WeexSDK/Sources/Display/WXComponent+Display.m
+++ b/ios/sdk/WeexSDK/Sources/Display/WXComponent+Display.m
@@ -20,6 +20,7 @@
 #import "WXComponent+Display.h"
 #import "WXComponent.h"
 #import "WXComponent_internal.h"
+#import "WXComponent+BoxShadow.h"
 #import "WXLayer.h"
 #import "WXAssert.h"
 #import "WXUtility.h"
@@ -28,6 +29,8 @@
 #import "UIBezierPath+Weex.h"
 #import "WXRoundedRect.h"
 #import "WXSDKInstance.h"
+#import "WXDarkSchemeProtocol.h"
+#import "WXHandlerFactory.h"
 
 #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
 
@@ -101,6 +104,35 @@
     WXAssertMainThread();
 }
 
+- (void)schemeDidChange:(NSString*)scheme
+{
+    WXAssertMainThread();
+    if (_view) {
+        if (![self _needsDrawBorder]) {
+            _layer.borderColor = [self.weexInstance chooseColor:_borderTopColor lightSchemeColor:_lightSchemeBorderTopColor darkSchemeColor:_darkSchemeBorderTopColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor;
+            _layer.backgroundColor = [self.weexInstance chooseColor:self.styleBackgroundColor lightSchemeColor:self.lightSchemeBackgroundColor darkSchemeColor:self.darkSchemeBackgroundColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor;
+        }
+        else {
+            [self setNeedsDisplay];
+        }
+        
+        if (_backgroundImage) {
+            [self setGradientLayer];
+        }
+        
+        WXBoxShadow* usingBoxShadow = [self _chooseBoxShadow];
+        if (usingBoxShadow) {
+            _lastBoxShadow = usingBoxShadow;
+            [self configBoxShadow:usingBoxShadow];
+        }
+    }
+}
+
+- (WXColorScene)colorSceneType
+{
+    return WXColorSceneUnknown;
+}
+
 #pragma mark Private
 
 - (WXDisplayBlock)_displayBlock
@@ -289,7 +321,7 @@
 - (void)_collectCompositingDisplayBlocks:(NSMutableArray *)displayBlocks context:(CGContextRef)context isCancelled:(BOOL(^)(void))isCancelled
 {
     // TODO: compositingChild has no chance to applyPropertiesToView, need update here?
-    UIColor *backgroundColor = _backgroundColor;
+    UIColor *backgroundColor = [self.weexInstance chooseColor:self.styleBackgroundColor lightSchemeColor:self.lightSchemeBackgroundColor darkSchemeColor:self.darkSchemeBackgroundColor invert:self.invertForDarkScheme scene:[self colorSceneType]];
     BOOL clipsToBounds = _clipToBounds;
     CGRect frame = self.calculatedFrame;
     CGRect bounds = CGRectMake(0, 0, frame.size.width, frame.size.height);
@@ -349,13 +381,21 @@
     
     CGContextSetAlpha(context, _opacity);
     // fill background color
-    if (_backgroundColor && CGColorGetAlpha(_backgroundColor.CGColor) > 0) {
-        CGContextSetFillColorWithColor(context, _backgroundColor.CGColor);
-        UIBezierPath *bezierPath = [UIBezierPath wx_bezierPathWithRoundedRect:rect topLeft:topLeft topRight:topRight bottomLeft:bottomLeft bottomRight:bottomRight];
-        [bezierPath fill];
-        WXPerformBlockOnMainThread(^{
-            _view.backgroundColor = UIColor.clearColor;
-        });
+    UIColor* bgColor = [self.weexInstance chooseColor:self.styleBackgroundColor lightSchemeColor:self.lightSchemeBackgroundColor darkSchemeColor:self.darkSchemeBackgroundColor invert:self.invertForDarkScheme scene:[self colorSceneType]];
+    
+    if (bgColor && [bgColor respondsToSelector:@selector(CGColor)]) {
+        if (CGColorGetAlpha(bgColor.CGColor) > 0) {
+            CGContextSetFillColorWithColor(context, bgColor.CGColor);
+            UIBezierPath *bezierPath = [UIBezierPath wx_bezierPathWithRoundedRect:rect topLeft:topLeft topRight:topRight bottomLeft:bottomLeft bottomRight:bottomRight];
+            [bezierPath fill];
+            __weak WXComponent* wself = self;
+            WXPerformBlockOnMainThread(^{
+                __strong WXComponent* sself = wself;
+                if (sself) {
+                    sself->_view.backgroundColor = UIColor.clearColor;
+                }
+            });
+        }
     }
     // Top
     if (_borderTopWidth > 0) {
@@ -367,7 +407,8 @@
             CGContextSetLineDash(context, 0, 0, 0);
         }
         CGContextSetLineWidth(context, _borderTopWidth);
-        CGContextSetStrokeColorWithColor(context, _borderTopColor.CGColor);
+        CGContextSetStrokeColorWithColor(context,
+                                         [self.weexInstance chooseColor:_borderTopColor lightSchemeColor:_lightSchemeBorderTopColor darkSchemeColor:_darkSchemeBorderTopColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor);
         CGContextAddArc(context, size.width-topRight, topRight, topRight-_borderTopWidth/2, -M_PI_4+(_borderRightWidth>0?0:M_PI_4), -M_PI_2, 1);
         CGContextMoveToPoint(context, size.width-topRight, _borderTopWidth/2);
         CGContextAddLineToPoint(context, topLeft, _borderTopWidth/2);
@@ -388,7 +429,8 @@
             CGContextSetLineDash(context, 0, 0, 0);
         }
         CGContextSetLineWidth(context, _borderLeftWidth);
-        CGContextSetStrokeColorWithColor(context, _borderLeftColor.CGColor);
+        CGContextSetStrokeColorWithColor(context,
+                                         [self.weexInstance chooseColor:_borderLeftColor lightSchemeColor:_lightSchemeBorderLeftColor darkSchemeColor:_darkSchemeBorderLeftColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor);
         CGContextAddArc(context, topLeft, topLeft, topLeft-_borderLeftWidth/2, -M_PI, -M_PI_2-M_PI_4+(_borderTopWidth > 0?0:M_PI_4), 0);
         CGContextMoveToPoint(context, _borderLeftWidth/2, topLeft);
         CGContextAddLineToPoint(context, _borderLeftWidth/2, size.height-bottomLeft);
@@ -409,7 +451,8 @@
             CGContextSetLineDash(context, 0, 0, 0);
         }
         CGContextSetLineWidth(context, _borderBottomWidth);
-        CGContextSetStrokeColorWithColor(context, _borderBottomColor.CGColor);
+        CGContextSetStrokeColorWithColor(context,
+                                         [self.weexInstance chooseColor:_borderBottomColor lightSchemeColor:_lightSchemeBorderBottomColor darkSchemeColor:_darkSchemeBorderBottomColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor);
         CGContextAddArc(context, bottomLeft, size.height-bottomLeft, bottomLeft-_borderBottomWidth/2, M_PI-M_PI_4+(_borderLeftWidth>0?0:M_PI_4), M_PI_2, 1);
         CGContextMoveToPoint(context, bottomLeft, size.height-_borderBottomWidth/2);
         CGContextAddLineToPoint(context, size.width-bottomRight, size.height-_borderBottomWidth/2);
@@ -430,7 +473,8 @@
             CGContextSetLineDash(context, 0, 0, 0);
         }
         CGContextSetLineWidth(context, _borderRightWidth);
-        CGContextSetStrokeColorWithColor(context, _borderRightColor.CGColor);
+        CGContextSetStrokeColorWithColor(context,
+                                         [self.weexInstance chooseColor:_borderRightColor lightSchemeColor:_lightSchemeBorderRightColor darkSchemeColor:_darkSchemeBorderRightColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor);
         CGContextAddArc(context, size.width-bottomRight, size.height-bottomRight, bottomRight-_borderRightWidth/2, M_PI_4+(_borderBottomWidth>0?0:M_PI_4), 0, 1);
         CGContextMoveToPoint(context, size.width-_borderRightWidth/2, size.height-bottomRight);
         CGContextAddLineToPoint(context, size.width-_borderRightWidth/2, topRight);
@@ -486,7 +530,17 @@
     if (!radiusEqual) {
         return YES;
     }
-    BOOL colorEqual = [_borderTopColor isEqual:_borderRightColor] && [_borderRightColor isEqual:_borderBottomColor] && [_borderBottomColor isEqual:_borderLeftColor];
+    
+    BOOL invert = self.invertForDarkScheme;
+    WXColorScene scene = [self colorSceneType];
+    UIColor* usingBorderTopColor = [self.weexInstance chooseColor:_borderTopColor lightSchemeColor:_lightSchemeBorderTopColor darkSchemeColor:_darkSchemeBorderTopColor invert:invert scene:scene];
+    UIColor* usingBorderRightColor = [self.weexInstance chooseColor:_borderRightColor lightSchemeColor:_lightSchemeBorderRightColor darkSchemeColor:_darkSchemeBorderRightColor invert:invert scene:scene];
+    UIColor* usingBorderBottomColor = [self.weexInstance chooseColor:_borderBottomColor lightSchemeColor:_lightSchemeBorderBottomColor darkSchemeColor:_darkSchemeBorderBottomColor invert:invert scene:scene];
+    UIColor* usingBorderLeftColor = [self.weexInstance chooseColor:_borderLeftColor lightSchemeColor:_lightSchemeBorderLeftColor darkSchemeColor:_darkSchemeBorderLeftColor invert:invert scene:scene];
+    
+    BOOL colorEqual = [usingBorderTopColor isEqual:usingBorderRightColor] &&
+        [usingBorderRightColor isEqual:usingBorderBottomColor] &&
+        [usingBorderBottomColor isEqual:usingBorderLeftColor];
     if (!colorEqual) {
         return YES;
     }
@@ -579,6 +633,58 @@
     
     WX_CHECK_BORDER_PROP(Style, Top, Left, Bottom, Right, WXBorderStyle)
     WX_CHECK_BORDER_PROP(Color, Top, Left, Bottom, Right, UIColor)
+    do {
+        BOOL needsDisplay = NO;
+        if (styles[@"weexDarkSchemeBorderColor"]) {
+            _darkSchemeBorderTopColor = _darkSchemeBorderLeftColor = _darkSchemeBorderRightColor = _darkSchemeBorderBottomColor = [WXConvert UIColor:styles[@"weexDarkSchemeBorderColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexDarkSchemeBorderTopColor"]) {
+            _darkSchemeBorderTopColor = [WXConvert UIColor:styles[@"weexDarkSchemeBorderTopColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexDarkSchemeBorderLeftColor"]) {
+            _darkSchemeBorderLeftColor = [WXConvert UIColor:styles[@"weexDarkSchemeBorderLeftColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexDarkSchemeBorderRightColor"]) {
+            _darkSchemeBorderRightColor = [WXConvert UIColor:styles[@"weexDarkSchemeBorderRightColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexDarkSchemeBorderBottomColor"]) {
+            _darkSchemeBorderBottomColor = [WXConvert UIColor:styles[@"weexDarkSchemeBorderBottomColor"]];
+            needsDisplay = YES;
+        }
+        if (needsDisplay && updating) {
+            [self setNeedsDisplay];
+        }
+    } while (0);
+    do {
+        BOOL needsDisplay = NO;
+        if (styles[@"weexLightSchemeBorderColor"]) {
+            _lightSchemeBorderTopColor = _lightSchemeBorderLeftColor = _lightSchemeBorderRightColor = _lightSchemeBorderBottomColor = [WXConvert UIColor:styles[@"weexLightSchemeBorderColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexLightSchemeBorderTopColor"]) {
+            _lightSchemeBorderTopColor = [WXConvert UIColor:styles[@"weexLightSchemeBorderTopColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexLightSchemeBorderLeftColor"]) {
+            _lightSchemeBorderLeftColor = [WXConvert UIColor:styles[@"weexLightSchemeBorderLeftColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexLightSchemeBorderRightColor"]) {
+            _lightSchemeBorderRightColor = [WXConvert UIColor:styles[@"weexLightSchemeBorderRightColor"]];
+            needsDisplay = YES;
+        }
+        if (styles[@"weexLightSchemeBorderBottomColor"]) {
+            _lightSchemeBorderBottomColor = [WXConvert UIColor:styles[@"weexLightSchemeBorderBottomColor"]];
+            needsDisplay = YES;
+        }
+        if (needsDisplay && updating) {
+            [self setNeedsDisplay];
+        }
+    } while (0);
     WX_CHECK_BORDER_PROP_PIXEL(Width, Top, Left, Bottom, Right)
     WX_CHECK_BORDER_PROP_PIXEL(Radius, TopLeft, TopRight, BottomLeft, BottomRight)
 
@@ -592,9 +698,9 @@
         } else if (!nowNeedsDrawBorder) {
             [self _resetNativeBorderRadius];
             _layer.borderWidth = _borderTopWidth;
-            _layer.borderColor = _borderTopColor.CGColor;
+            _layer.borderColor = [self.weexInstance chooseColor:_borderTopColor lightSchemeColor:_lightSchemeBorderTopColor darkSchemeColor:_darkSchemeBorderTopColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor;
             if ((_transition.transitionOptions & WXTransitionOptionsBackgroundColor) != WXTransitionOptionsBackgroundColor ) {
-                _layer.backgroundColor = _backgroundColor.CGColor;
+                _layer.backgroundColor = [self.weexInstance chooseColor:self.styleBackgroundColor lightSchemeColor:self.lightSchemeBackgroundColor darkSchemeColor:self.darkSchemeBackgroundColor invert:self.invertForDarkScheme scene:[self colorSceneType]].CGColor;
             }
         }
     }
@@ -606,7 +712,8 @@
     WXRoundedRect *borderRect = [[WXRoundedRect alloc] initWithRect:rect topLeft:_borderTopLeftRadius topRight:_borderTopRightRadius bottomLeft:_borderBottomLeftRadius bottomRight:_borderBottomRightRadius];
     WXRadii *radii = borderRect.radii;
     BOOL hasBorderRadius = [radii hasBorderRadius];
-    return (!hasBorderRadius) && _opacity == 1.0 && CGColorGetAlpha(_backgroundColor.CGColor) == 1.0 && [self _needsDrawBorder];
+    UIColor* currentBgColor = [self.weexInstance chooseColor:self.styleBackgroundColor lightSchemeColor:self.lightSchemeBackgroundColor darkSchemeColor:self.darkSchemeBackgroundColor invert:self.invertForDarkScheme scene:[self colorSceneType]];
+    return (!hasBorderRadius) && _opacity == 1.0 && CGColorGetAlpha(currentBgColor.CGColor) == 1.0 && [self _needsDrawBorder];
 }
 
 - (CAShapeLayer *)drawBorderRadiusMaskLayer:(CGRect)rect
@@ -627,6 +734,24 @@
     return _borderTopLeftRadius > 0.001 || _borderTopRightRadius > 0.001 || _borderBottomLeftRadius > 0.001 || _borderBottomLeftRadius > 0.001;
 }
 
+- (WXBoxShadow*)_chooseBoxShadow
+{
+    if ([self.weexInstance isDarkScheme]) {
+        if (_darkSchemeBoxShadow) {
+            return _darkSchemeBoxShadow;
+        }
+        else {
+            return _boxShadow;
+        }
+    }
+    else if (_lightSchemeBoxShadow) {
+        return _lightSchemeBoxShadow;
+    }
+    else {
+        return _boxShadow;
+    }
+}
+
 #pragma mark - Deprecated
 
 - (WXDisplayBlock)displayBlock
diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
index ad181ac..2039300 100644
--- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
+++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
@@ -29,6 +29,7 @@
 #import "WXNavigationDefaultImpl.h"
 #import "WXURLRewriteDefaultImpl.h"
 #import "WXJSFrameworkLoadDefaultImpl.h"
+#import "WXDarkSchemeDefaultImpl.h"
 
 #import "WXSDKManager.h"
 #import "WXSDKError.h"
@@ -205,6 +206,7 @@
     [self registerHandler:[WXNavigationDefaultImpl new] withProtocol:@protocol(WXNavigationProtocol)];
     [self registerHandler:[WXURLRewriteDefaultImpl new] withProtocol:@protocol(WXURLRewriteProtocol)];
     [self registerHandler:[WXJSFrameworkLoadDefaultImpl new] withProtocol:@protocol(WXJSFrameworkLoadProtocol)];
+    [self registerHandler:[WXDarkSchemeDefaultImpl new] withProtocol:@protocol(WXDarkSchemeProtocol)];
 }
 
 + (void)registerHandler:(id)handler withProtocol:(Protocol *)protocol
@@ -225,6 +227,12 @@
 
 + (void)initSDKEnvironment
 {
+    if (@available(iOS 13.0, *)) {
+    }
+    else {
+        [WXUtility setDarkSchemeSupportEnable:NO];
+    }
+    
     NSString *fileName = @"weex-main-jsfm";
     NSString *filePath = [[NSBundle bundleForClass:self] pathForResource:fileName ofType:@"js"];
 	if (filePath == nil) {
diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h
index b628b06..7523cf9 100644
--- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h
+++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h
@@ -88,6 +88,7 @@
     WX_KEY_EXCEPTION_JS_DOWNLOAD =-9200,
     WX_KEY_EXCEPTION_DOM = -9300,
     WX_KEY_EXCEPTION_WXBRIDGE=-9400,
+    WX_KEY_EXCEPTION_JS_THREAD_BLOCK=-9401,
     
     // The following error codes have a remapped value defined in WXSDKUniversalErrCode
     WX_KEY_EXCEPTION_DEGRADE = -9500,
@@ -106,8 +107,8 @@
     WX_KEY_EXCEPTION_EMPTY_SCREEN_JS = -9700,
     WX_KEY_EXCEPTION_EMPTY_SCREEN_NATIVE = -9701,
     
-    WX_KEY_EXCEPTION_TOO_MANY_TIMERS = -9800,
     WX_KEY_EXCEPTION_NO_BUNDLE_TYPE = -9801,
+    WX_KEY_EXCEPTION_INVALID_JSON_OBJECT = -9802,
     
     WX_KEY_EXCEPTION_HERON_ERROR = -9900,
     WX_KEY_EXCEPTION_HERON_RENDER_ERROR = -9901,
diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m
index 07ccbe1..755cdd1 100644
--- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m
+++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m
@@ -88,6 +88,7 @@
                 @(WX_KEY_EXCEPTION_JS_DOWNLOAD):@{ERROR_TYPE:@(WX_DOWN_LOAD_ERROR),ERROR_GROUP:@(WX_NATIVE)},
                 @(WX_KEY_EXCEPTION_DOM):@{ERROR_TYPE:@(WX_NATIVE_ERROR),ERROR_GROUP:@(WX_NATIVE)},
                 @(WX_KEY_EXCEPTION_WXBRIDGE):@{ERROR_TYPE:@(WX_JS_ERROR),ERROR_GROUP:@(WX_JS)},
+                @(WX_KEY_EXCEPTION_JS_THREAD_BLOCK):@{ERROR_TYPE:@(WX_JS_ERROR),ERROR_GROUP:@(WX_JS)},
                 
                 @(WX_KEY_EXCEPTION_DEGRADE):@{ERROR_TYPE:@(WX_DEGRADE_ERROR),ERROR_GROUP:@(WX_NATIVE),ERROR_ALIAS:@(WX_UNI_KEY_EXCEPTION_DEGRADE)},
                 @(WX_KEY_EXCEPTION_DEGRADE_CHECK_CONTENT_LENGTH_FAILED):@{ERROR_TYPE:@(WX_DEGRADE_ERROR),ERROR_GROUP:@(WX_NET),ERROR_ALIAS:@(WX_UNI_KEY_EXCEPTION_DEGRADE_CHECK_CONTENT_LENGTH_FAILED)},
@@ -103,9 +104,10 @@
                 @(WX_KEY_EXCEPTION_EMPTY_SCREEN_JS):@{ERROR_TYPE:@(WX_RENDER_ERROR),ERROR_GROUP:@(WX_JS)},
                 @(WX_KEY_EXCEPTION_EMPTY_SCREEN_NATIVE):@{ERROR_TYPE:@(WX_RENDER_ERROR),ERROR_GROUP:@(WX_NATIVE)},
                 
-                @(WX_KEY_EXCEPTION_TOO_MANY_TIMERS):@{ERROR_TYPE:@(WX_NATIVE_ERROR),ERROR_GROUP:@(WX_NATIVE)},
                 @(WX_KEY_EXCEPTION_NO_BUNDLE_TYPE):@{ERROR_TYPE:@(WX_JS_ERROR),ERROR_GROUP:@(WX_JS)},
                 
+                @(WX_KEY_EXCEPTION_INVALID_JSON_OBJECT):@{ERROR_TYPE:@(WX_JS_ERROR),ERROR_GROUP:@(WX_JS)},
+                
                 @(WX_KEY_EXCEPTION_HERON_ERROR):@{ERROR_TYPE:@(WX_NATIVE_ERROR),ERROR_GROUP:@(WX_NATIVE)},
                 @(WX_KEY_EXCEPTION_HERON_RENDER_ERROR):@{ERROR_TYPE:@(WX_RENDER_ERROR),ERROR_GROUP:@(WX_NATIVE)},
                 };
diff --git a/ios/sdk/WeexSDK/Sources/Handler/WXDarkSchemeDefaultImpl.h b/ios/sdk/WeexSDK/Sources/Handler/WXDarkSchemeDefaultImpl.h
new file mode 100644
index 0000000..1bc1d2e
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Handler/WXDarkSchemeDefaultImpl.h
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <Foundation/Foundation.h>
+#import <WeexSDK/WXDarkSchemeProtocol.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/* By default, this implementation class do basic invert of UIColor of RGBA color space.
+ You should implementation your own handler to better handle dark scheme in your application.
+ */
+@interface WXDarkSchemeDefaultImpl : NSObject <WXDarkSchemeProtocol>
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ios/sdk/WeexSDK/Sources/Handler/WXDarkSchemeDefaultImpl.m b/ios/sdk/WeexSDK/Sources/Handler/WXDarkSchemeDefaultImpl.m
new file mode 100644
index 0000000..ccae67b
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Handler/WXDarkSchemeDefaultImpl.m
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "WXDarkSchemeDefaultImpl.h"
+
+@implementation WXDarkSchemeDefaultImpl
+
+- (BOOL)defaultInvertValueForRootComponent
+{
+    return NO;
+}
+
+- (void)configureView:(UIView *)view ofComponent:(WXComponent *)component
+{
+    // Nothing
+}
+
+- (UIColor *_Nullable)getInvertedColorFor:(UIColor *_Nonnull)color ofScene:(WXColorScene)scene withDefault:(UIColor *_Nullable)defaultColor
+{
+    CGFloat red, blue, green, alpha;
+    if ([color getRed:&red green:&green blue:&blue alpha:&alpha]) {
+        return [UIColor colorWithRed:1 - red green:1 - green blue:1 - blue alpha:alpha];
+    }
+    return color;
+}
+
+@end
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
index a56cd64..fd5eb88 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
@@ -135,13 +135,14 @@
                 strongSelf.layer.transform = CATransform3DIdentity;
             }
             
+            WXBoxShadow* usingBoxShadow = [strongSelf _chooseBoxShadow];            
             if (!CGRectEqualToRect(strongSelf.view.frame,strongSelf.calculatedFrame)) {
                 strongSelf.view.frame = strongSelf.calculatedFrame;
                 strongSelf->_absolutePosition = CGPointMake(NAN, NAN);
-                [strongSelf configBoxShadow:strongSelf->_boxShadow];
+                [strongSelf configBoxShadow:usingBoxShadow];
             } else {
-                if (![strongSelf equalBoxShadow:strongSelf->_boxShadow withBoxShadow:strongSelf->_lastBoxShadow]) {
-                    [strongSelf configBoxShadow:strongSelf->_boxShadow];
+                if (![strongSelf equalBoxShadow:usingBoxShadow withBoxShadow:strongSelf->_lastBoxShadow]) {
+                    [strongSelf configBoxShadow:usingBoxShadow];
                 }
             }
             
diff --git a/ios/sdk/WeexSDK/Sources/Loader/WXResourceLoader.m b/ios/sdk/WeexSDK/Sources/Loader/WXResourceLoader.m
index 9015625..8423f78 100644
--- a/ios/sdk/WeexSDK/Sources/Loader/WXResourceLoader.m
+++ b/ios/sdk/WeexSDK/Sources/Loader/WXResourceLoader.m
@@ -140,14 +140,7 @@
     WXLogDebug(@"request:%@ didReceiveResponse:%@ ", request, response);
     
     _response = response;
-    id<WXConfigCenterProtocol> configCenter = [WXSDKEngine handlerForProtocol:@protocol(WXConfigCenterProtocol)];
-    if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) {
-        BOOL isDefault;
-        BOOL clearResponseData = [[configCenter configForKey:@"iOS_weex_ext_config.clearResponseDataWhenDidReceiveResponse" defaultValue:@(NO) isDefault:&isDefault] boolValue];
-        if(clearResponseData) {
-            _data = nil;
-        }
-    }
+    _data = nil;
     
     if (self.onResponseReceived) {
         self.onResponseReceived(response);
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
index 3b1d2a4..5fc9c54 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
@@ -45,6 +45,10 @@
  **/
 @property (nonatomic, weak, readonly) WXSDKInstance *topInstance;
 
+@property (nonatomic, strong) NSMutableDictionary *lastMethodInfo;
+
++ (instancetype)sharedManager;
+
 /**
  *  Create Instance Method
  *  @param instance  :   instance id
@@ -246,6 +250,8 @@
 
 - (void)executeJSTaskQueue;
 
+- (void)checkJSThread;
+
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
index ff89cfc..4f6a3f2 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
@@ -37,6 +37,9 @@
 #import "WXDataRenderHandler.h"
 #import "WXHandlerFactory.h"
 #import "WXUtility.h"
+#import "WXExceptionUtils.h"
+#import "WXSDKEngine.h"
+#import "WXConfigCenterProtocol.h"
 
 @interface WXBridgeManager ()
 
@@ -46,6 +49,7 @@
 @property (nonatomic, strong) WXBridgeContext *backupBridgeCtx;
 @property (nonatomic, strong) WXThreadSafeMutableArray *instanceIdStack;
 @property (nonatomic, strong) NSMutableArray* jsTaskQueue;
+@property (nonatomic, strong) NSTimer *timer;
 
 @end
 
@@ -71,10 +75,20 @@
         _bridgeCtx = [[WXBridgeContext alloc] init];
         _supportMultiJSThread = NO;
         _jsTaskQueue = [NSMutableArray array];
+        _timer = nil;
+        _lastMethodInfo = [NSMutableDictionary dictionary];
     }
     return self;
 }
 
+- (WXBridgeContext *)bridgeCtx {
+    if (_bridgeCtx) {
+        return _bridgeCtx;
+    }
+    _bridgeCtx = [[WXBridgeContext alloc] init];
+    return _bridgeCtx;
+}
+
 - (WXBridgeContext *)backupBridgeCtx {
     if (_backupBridgeCtx) {
         return _backupBridgeCtx;
@@ -120,7 +134,7 @@
         [WXBridgeThread setQualityOfService:[[NSThread mainThread] qualityOfService]];
         [WXBridgeThread start];
     });
-    
+
     return WXBridgeThread;
 }
 
@@ -778,6 +792,42 @@
     }, instanceId);
 }
 
+#pragma mark JS Thread Check
+- (void)checkJSThread {
+    if (!_timer) {
+        id configCenter = [WXSDKEngine handlerForProtocol:@protocol(WXConfigCenterProtocol)];
+        if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) {
+            BOOL enableCheckJSThread = [[configCenter configForKey:@"iOS_weex_ext_config.enable_check_js_thread" defaultValue:@(YES) isDefault:NULL] boolValue];
+            if (enableCheckJSThread) {
+                _timer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(_postTaskToBridgeThread) userInfo:nil repeats:YES];
+            }
+        }
+    }
+}
+
+- (void)_postTaskToBridgeThread {
+    __block BOOL taskFinished = NO;
+    WXPerformBlockOnBridgeThread(^{
+        taskFinished = YES;
+    });
+
+    __weak typeof(self) weakSelf = self;
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if (!weakSelf) {
+            return;
+        }
+        if (!taskFinished) {
+            WXSDKErrCode errorCode = WX_KEY_EXCEPTION_JS_THREAD_BLOCK;
+            WXSDKInstance* instance = weakSelf.topInstance;
+            if (!instance) {
+                return;
+            }
+            NSString *instanceId = instance.instanceId;
+            [WXExceptionUtils commitCriticalExceptionRT:instanceId errCode:[NSString stringWithFormat:@"%d", errorCode] function:@"" exception:@"JS Thread is block" extParams:weakSelf.lastMethodInfo];
+        }
+    });
+}
+
 #pragma mark - Deprecated
 
 - (void)executeJsMethod:(WXCallJSMethod *)method
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
index f4b29a8..3f228ee 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
@@ -42,6 +42,7 @@
 #import "WXComponent_performance.h"
 #import "WXAnalyzerCenter.h"
 #import "WXDisplayLinkManager.h"
+#import "WXDarkSchemeProtocol.h"
 
 static NSThread *WXComponentThread;
 
@@ -261,6 +262,12 @@
     
     _rootComponent = [self _buildComponent:ref type:type supercomponent:nil styles:styles attributes:attributes events:events renderObject:renderObject];
     
+    if ([WXUtility isDarkSchemeSupportEnabled]) {
+        if (attributes[@"invertForDarkScheme"] == nil) {
+            _rootComponent.invertForDarkScheme = [[WXSDKInstance darkSchemeColorHandler] defaultInvertValueForRootComponent];
+        }
+    }
+    
     CGSize size = _weexInstance.frame.size;
     [WXCoreBridge setDefaultDimensionIntoRoot:_weexInstance.instanceId
                                         width:size.width height:size.height
@@ -327,6 +334,11 @@
         }
     }
     
+    // Not explicitly declare "invertForDarkScheme", inherit
+    if (attributes[@"invertForDarkScheme"] == nil) {
+        component.invertForDarkScheme = supercomponent.invertForDarkScheme;
+    }
+    
 #ifdef DEBUG
     WXLogDebug(@"flexLayout -> _recursivelyAddComponent : super:(%@,%@):[%f,%f] ,child:(%@,%@):[%f,%f],childClass:%@",
                supercomponent.type,
@@ -919,6 +931,9 @@
     [self _addUITask:^{
         UIView *rootView = instance.rootView;
         [instance.performance onInstanceRenderSuccess:instance];
+        if (instance.wlasmRender) {
+            [instance.apmInstance forceSetInteractionTime:[WXUtility getUnixFixTimeMillis]];
+        }
         if (instance.renderFinish) {
             instance.renderFinish(rootView);
         }
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXSDKManager.m b/ios/sdk/WeexSDK/Sources/Manager/WXSDKManager.m
index de71a29..9d16d1c 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXSDKManager.m
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXSDKManager.m
@@ -47,7 +47,7 @@
 - (instancetype)init
 {
     if (self = [super init]){
-        _bridgeMgr = [[WXBridgeManager alloc] init];
+        _bridgeMgr = [WXBridgeManager sharedManager];
     }
     return self;
 }
@@ -57,7 +57,7 @@
     WXBridgeManager* result = [self sharedInstance].bridgeMgr;
     if (result == nil) {
         // devtool may invoke "unload" and set bridgeMgr to nil
-        result = [[WXBridgeManager alloc] init];
+        result = [WXBridgeManager sharedManager];
         [self sharedInstance].bridgeMgr = result;
     }
     return result;
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.h b/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
index 0528b1d..54ba69e 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
@@ -32,6 +32,12 @@
     WXComponentUpdateStylesCallback
 } WXComponentCallbackType;
 
+typedef enum : NSUInteger {
+    WXColorSceneBackground,
+    WXColorSceneText,
+    WXColorSceneUnknown,
+} WXColorScene;
+
 /**
  * @abstract the component callback , result can be string or dictionary.
  * @discussion callback data to js, the id of callback function will be removed to save memory.
@@ -364,6 +370,8 @@
 /// @name Display
 ///--------------------------------------
 
+@property (nonatomic, assign) BOOL invertForDarkScheme;
+
 @property (nonatomic, assign) WXDisplayType displayType;
 
 /**
@@ -379,6 +387,16 @@
 - (BOOL)needsDrawRect;
 
 /**
+ * @abstract Fired on instance scheme did changed.
+ */
+- (void)schemeDidChange:(NSString*)scheme;
+
+/**
+ * @abstract Hint used for better do color invert in dark mode.
+ */
+- (WXColorScene)colorSceneType;
+
+/**
  * @abstract Draws the component’s image within the passed-in rectangle.
  * @parameter rect The rectangle which is the entire visible bounds of your component. 
  * @return A UIImage containing the contents of the current bitmap graphics context.
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
index a60251c..cb6251c 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
@@ -42,6 +42,7 @@
 #import "WXSDKInstance_performance.h"
 #import "WXComponent_performance.h"
 #import "WXCoreBridge.h"
+#import "WXDarkSchemeProtocol.h"
 
 #pragma clang diagnostic ignored "-Wincomplete-implementation"
 #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
@@ -70,6 +71,9 @@
 }
 
 @synthesize transform = _transform;
+@synthesize styleBackgroundColor = _styleBackgroundColor;
+@synthesize darkSchemeBackgroundColor = _darkSchemeBackgroundColor;
+@synthesize lightSchemeBackgroundColor = _lightSchemeBackgroundColor;
 
 #pragma mark Life Cycle
 
@@ -103,6 +107,7 @@
         _eventPenetrationEnabled = NO;
         _accessibilityHintContent = nil;
         _cancelsTouchesInView = YES;
+        _invertForDarkScheme = NO;
         
         _async = NO;
         
@@ -121,6 +126,10 @@
             }
         }
         
+        if (attributes[@"invertForDarkScheme"]) {
+            _invertForDarkScheme = [WXConvert BOOL:attributes[@"invertForDarkScheme"]];
+        }
+        
         if (attributes[@"userInteractionEnabled"]) {
             _userInteractionEnabled = [WXConvert BOOL:attributes[@"userInteractionEnabled"]];
         }
@@ -379,6 +388,12 @@
         [self viewWillLoad];
         
         _view = [self loadView];
+        
+        // Provide a chance for dark scheme handler to process the view
+        if ([WXUtility isDarkSchemeSupportEnabled]) {
+            [[WXSDKInstance darkSchemeColorHandler] configureView:_view ofComponent:self];
+        }
+        
 #ifdef DEBUG
         WXLogDebug(@"flexLayout -> loadView:addr-(%p),componentRef-(%@)",_view,self.ref);
 #endif
@@ -387,11 +402,37 @@
         _view.hidden = _visibility == WXVisibilityShow ? NO : YES;
         _view.clipsToBounds = _clipToBounds;
         if (![self _needsDrawBorder]) {
-            _layer.borderColor = _borderTopColor.CGColor;
+            _layer.borderColor = [self.weexInstance chooseColor:_borderTopColor lightSchemeColor:_lightSchemeBorderTopColor darkSchemeColor:_darkSchemeBorderTopColor invert:_invertForDarkScheme scene:[self colorSceneType]].CGColor;
             _layer.borderWidth = _borderTopWidth;
             [self _resetNativeBorderRadius];
             _layer.opacity = _opacity;
-            _view.backgroundColor = _backgroundColor;
+            
+            /* Also set background color to view to fix that problem that system may
+             set dynamic color to UITableView. Without these codes, event if we set
+             clear color to layer, the table view could not be transparent. */
+            if ([WXUtility isDarkSchemeSupportEnabled]) {
+                UIColor* choosedColor = [self.weexInstance chooseColor:self.styleBackgroundColor lightSchemeColor:self.lightSchemeBackgroundColor darkSchemeColor:self.darkSchemeBackgroundColor invert:_invertForDarkScheme scene:[self colorSceneType]];
+                if (choosedColor == [UIColor clearColor]) {
+                    _view.backgroundColor = choosedColor;
+                }
+                _layer.backgroundColor = choosedColor.CGColor;
+            }
+            else {
+                /* On iOS10, there is an annoying problem that if we only
+                 set backgroundColor to layer(not to view), for UIScrollView
+                 the background color would be black. So we have to set
+                 background color to UIView itself on iOS10(or lower).
+                 
+                 For iOS13, we have SDK which hooked setBackgroundColor
+                 of UIView to support autoinverting(no in WeexSDK).
+                 But that SDK would finally set a UIDynamicColor to view.
+                 Weex can handle dark mode, so we don't want background
+                 color of a UIView in Weex page to be set to UIDynamicColor.
+                 So in code above, we only set color to layer but which
+                 also caused the black problem that on iOS10.
+                 */
+                _view.backgroundColor = self.styleBackgroundColor;
+            }
         }
 
         if (_backgroundImage) {
@@ -404,8 +445,10 @@
         
         [self _adjustForRTL];
         
-        if (_boxShadow) {
-            [self configBoxShadow:_boxShadow];
+        WXBoxShadow* usingBoxShadow = [self _chooseBoxShadow];        
+        if (usingBoxShadow) {
+            _lastBoxShadow = usingBoxShadow;
+            [self configBoxShadow:usingBoxShadow];
         }
         
         _view.wx_component = self;
@@ -844,7 +887,25 @@
     if (CGRectEqualToRect(self.view.frame, CGRectZero)) {
         return;
     }
-    NSDictionary * linearGradient = [WXUtility linearGradientWithBackgroundImage:_backgroundImage];
+    
+    NSString* styleValue = nil;
+    BOOL isDark = [self.weexInstance isDarkScheme];
+    if (isDark) {
+        if (_darkSchemeBackgroundImage) {
+            styleValue = _darkSchemeBackgroundImage;
+        }
+        else {
+            styleValue = _backgroundImage;
+        }
+    }
+    else if (_lightSchemeBackgroundImage) {
+        styleValue = _lightSchemeBackgroundImage;
+    }
+    else {
+        styleValue = _backgroundImage;
+    }
+    
+    NSDictionary * linearGradient = [WXUtility linearGradientWithBackgroundImage:styleValue];
     if (!linearGradient) {
         return ;
     }
@@ -853,12 +914,13 @@
     dispatch_async(dispatch_get_main_queue(), ^{
         __strong typeof(self) strongSelf = weakSelf;
         if(strongSelf) {
+            // No need to auto-invert linear-gradient colors. We only allows using 'dark-scheme-background-image' style.
             UIColor * startColor = (UIColor*)linearGradient[@"startColor"];
             UIColor * endColor = (UIColor*)linearGradient[@"endColor"];
             CAGradientLayer * gradientLayer = [WXUtility gradientLayerFromColors:@[startColor, endColor] locations:nil frame:strongSelf.view.bounds gradientType:(WXGradientType)[linearGradient[@"gradientType"] integerValue]];
             if (gradientLayer) {
-                _backgroundColor = [UIColor colorWithPatternImage:[strongSelf imageFromLayer:gradientLayer]];
-                strongSelf.view.backgroundColor = _backgroundColor;
+                strongSelf.styleBackgroundColor = [UIColor colorWithPatternImage:[strongSelf imageFromLayer:gradientLayer]];
+                strongSelf.view.backgroundColor = strongSelf.styleBackgroundColor;
                 [strongSelf setNeedsDisplay];
             }
         }
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
index c6cf521..088d8ac 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
@@ -26,6 +26,8 @@
 #import <WeexSDK/WXApmForInstance.h>
 #import <WeexSDK/WXComponentManager.h>
 
+@protocol WXDarkSchemeProtocol;
+
 NS_ASSUME_NONNULL_BEGIN
 
 extern NSString *const bundleUrlOptionKey;
@@ -447,6 +449,36 @@
  */
 + (NSDictionary*)lastPageInfo;
 
+#pragma mark - Scheme Support
+
+/**
+ Handler for handling color invert.
+
+ @return Handler instance.
+ */
++ (id<WXDarkSchemeProtocol>)darkSchemeColorHandler;
+
+/**
+ Return true if current is dark scheme for this instance.
+ */
+- (BOOL)isDarkScheme;
+
+/**
+ Get/set interface style of current instance.
+ */
+- (NSString*)currentSchemeName;
+- (void)setCurrentSchemeName:(NSString*)name;
+
+/**
+ Choose final color between original color and dark-mode one.
+ Also considering invert.
+ */
+- (UIColor*)chooseColor:(UIColor*)originalColor
+       lightSchemeColor:(UIColor*)lightColor
+        darkSchemeColor:(UIColor*)darkColor
+                 invert:(BOOL)invert
+                  scene:(WXColorScene)scene;
+
 /** 
  * Deprecated 
  */
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
index 1a09028..70c7493 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
@@ -49,8 +49,10 @@
 #import "WXJSCoreBridge.h"
 #import "WXSDKInstance_performance.h"
 #import "WXPageEventNotifyEvent.h"
+#import "WXConvertUtility.h"
 #import "WXCoreBridge.h"
-#import <WeexSDK/WXDataRenderHandler.h>
+#import "WXDataRenderHandler.h"
+#import "WXDarkSchemeProtocol.h"
 
 #define WEEX_LITE_URL_SUFFIX           @"wlasm"
 #define WEEX_RENDER_TYPE_PLATFORM       @"platform"
@@ -101,6 +103,13 @@
 {
     self = [super init];
     if (self) {
+        if ([WXUtility isDarkSchemeSupportEnabled]) {
+            self.schemeName = [WXUtility isSystemInDarkScheme] ? @"dark" : @"light";
+        }
+        else {
+            self.schemeName = @"light";
+        }
+        
         _renderType = renderType;
         _appearState = YES;
         
@@ -537,9 +546,6 @@
     if (!self.userInfo[@"jsMainBundleStringContentLength"]) {
         self.userInfo[@"jsMainBundleStringContentLength"] = @([mainBundleString length]);
     }
-    if (!self.userInfo[@"jsMainBundleStringContentLength"]) {
-        self.userInfo[@"jsMainBundleStringContentMd5"] = [WXUtility md5:mainBundleString];
-    }
     
     id<WXPageEventNotifyEventProtocol> pageEvent = [WXSDKEngine handlerForProtocol:@protocol(WXPageEventNotifyEventProtocol)];
     if ([pageEvent respondsToSelector:@selector(pageStart:)]) {
@@ -599,6 +605,23 @@
     if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) {		
         BOOL enableRTLLayoutDirection = [[configCenter configForKey:@"iOS_weex_ext_config.enableRTLLayoutDirection" defaultValue:@(YES) isDefault:NULL] boolValue];
         [WXUtility setEnableRTLLayoutDirection:enableRTLLayoutDirection];
+        
+        BOOL isIOS13 = [[[UIDevice currentDevice] systemVersion] integerValue] == 13;
+        BOOL useMRCForInvalidJSONObject = [[configCenter configForKey:@"iOS_weex_ext_config.useMRCForInvalidJSONObject" defaultValue:@(YES) isDefault:NULL] boolValue];
+        BOOL alwaysUseMRCForObjectToWeexCore = [[configCenter configForKey:@"iOS_weex_ext_config.alwaysUseMRC" defaultValue:@(NO) isDefault:NULL] boolValue];
+        ConvertSwitches(isIOS13, useMRCForInvalidJSONObject, alwaysUseMRCForObjectToWeexCore);
+        
+        BOOL isDarkSchemeSupportEnabled = [[configCenter configForKey:@"iOS_weex_ext_config.supportDarkScheme" defaultValue:@(YES) isDefault:NULL] boolValue];
+        if (@available(iOS 13.0, *)) {
+        }
+        else {
+            isDarkSchemeSupportEnabled = NO;
+        }
+        [WXUtility setDarkSchemeSupportEnable:isDarkSchemeSupportEnabled];
+    }
+    else {
+        BOOL isIOS13 = [[[UIDevice currentDevice] systemVersion] integerValue] == 13;
+        ConvertSwitches(isIOS13, YES, NO);
     }
     return NO;
 }
@@ -949,7 +972,7 @@
 }
     
 - (BOOL)wlasmRender {
-    if ([_options[@"WLASM_RENDER"] boolValue]) {
+    if ([_options[@"WLASM_RENDER"] boolValue] || [_scriptURL.pathExtension isEqualToString:@"wlasm"] || [_scriptURL.pathExtension isEqualToString:@"wlm"]) {
         return YES;
     }
     return NO;
@@ -1162,6 +1185,104 @@
     return result;
 }
 
++ (id<WXDarkSchemeProtocol>)darkSchemeColorHandler
+{
+    static id<WXDarkSchemeProtocol> colorHandler;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        colorHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXDarkSchemeProtocol)];
+    });
+    return colorHandler;
+}
+
+- (NSString*)currentSchemeName
+{
+    return self.schemeName;
+}
+
+- (BOOL)isDarkScheme
+{
+    return [self.schemeName isEqualToString:@"dark"];
+}
+
+- (void)setCurrentSchemeName:(NSString*)name
+{
+    if (![WXUtility isDarkSchemeSupportEnabled]) {
+        self.schemeName = @"light";
+        return;
+    }
+    
+    if (name && ![name isEqualToString:self.schemeName]) {
+        self.schemeName = name;
+        
+        if (self.isCustomRenderType) {
+            return;
+        }
+        
+        // Recursively visit all components and notify that scheme had changed.
+        __weak WXSDKInstance* weakSelf = self;
+        WXPerformBlockOnComponentThread(^{
+            __strong WXSDKInstance* strongSelf = weakSelf;
+            if (strongSelf == nil) {
+                return;
+            }
+            
+            if (!strongSelf->_componentManager.isValid) {
+                return;
+            }
+            
+            [strongSelf->_componentManager enumerateComponentsUsingBlock:^(WXComponent * _Nonnull component, BOOL * _Nonnull stop) {
+                __weak WXComponent* wcomp = component;
+                WXPerformBlockOnMainThread(^{
+                    __strong WXComponent* scomp = wcomp;
+                    if (scomp) {
+                        [scomp schemeDidChange:name];
+                    }
+                });
+            }];
+        });
+        
+        [[WXSDKManager bridgeMgr] fireEvent:_instanceId
+                                        ref:WX_SDK_ROOT_REF
+                                       type:@"schemechange"
+                                     params:@{@"scheme": self.schemeName?:@"light"}
+                                 domChanges:nil];
+    }
+}
+
+- (UIColor*)chooseColor:(UIColor*)originalColor
+       lightSchemeColor:(UIColor*)lightColor
+        darkSchemeColor:(UIColor*)darkColor
+                 invert:(BOOL)invert
+                  scene:(WXColorScene)scene
+{
+    if (![WXUtility isDarkSchemeSupportEnabled]) {
+        return originalColor;
+    }
+    
+    if ([self isDarkScheme]) {
+        if (darkColor) {
+            return darkColor;
+        }
+        else if (invert) {
+            // Invert originalColor
+            if (originalColor == [UIColor clearColor]) {
+                return originalColor;
+            }
+            return [[WXSDKInstance darkSchemeColorHandler] getInvertedColorFor:originalColor ofScene:scene withDefault:originalColor];
+        }
+        else {
+            return originalColor;
+        }
+    }
+    else if (lightColor) {
+        return lightColor;
+    }
+    else {
+        return originalColor;
+    }
+}
+
 @end
 
 @implementation WXSDKInstance (Deprecated)
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h
index 25680da..d3811c7 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h
@@ -39,6 +39,8 @@
 @property (nonatomic, strong) NSString *createInstanceContextResult;
 @property (nonatomic, strong) NSString *executeRaxApiResult;
 
+@property (atomic, strong) NSString* schemeName;
+
 - (void)addModuleEventObservers:(NSString*)event callback:(NSString*)callbackId option:(NSDictionary*)option moduleClassName:(NSString*)moduleClassName;
 - (void)_addModuleEventObserversWithModuleMethod:(WXModuleMethod*)method;
 - (void)removeModuleEventObserver:(NSString*)event moduleClassName:(NSString*)moduleClassName;
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
index 8ee1591..67a19a5 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
@@ -26,6 +26,7 @@
 #import "WXLength.h"
 #import "WXTransition.h"
 #import "WXComponent+Layout.h"
+#import "WXDarkSchemeProtocol.h"
 
 @interface WXAnimationInfo : NSObject<NSCopying>
 
@@ -207,7 +208,40 @@
     }
     CAMediaTimingFunction *timingFunction = [WXConvert CAMediaTimingFunction:args[@"timingFunction"]];
     NSDictionary *styles = args[@"styles"];
+    NSDictionary* componentRawStyles = target.styles;
+    
+    BOOL isDarkScheme = [target.weexInstance isDarkScheme];
+    BOOL updatingDarkSchemeBackgroundColor = styles[@"weexDarkSchemeBackgroundColor"] != nil;
+    BOOL updatingLightSchemeBackgroundColor = styles[@"weexLightSchemeBackgroundColor"] != nil;
+    
     for (NSString *property in styles) {
+        if ([property isEqualToString:@"backgroundColor"]) {
+            if (isDarkScheme && (updatingDarkSchemeBackgroundColor ||
+                                componentRawStyles[@"weexDarkSchemeBackgroundColor"] != nil)) {
+                /* Updating "darkSchemeBackgroundColor" in dark mode,
+                 or this component has dark bg color explicitly defined in styels.
+                 We ignore transition animation for "backgroundColor" */
+                continue;
+            }
+            else if (!isDarkScheme && (updatingLightSchemeBackgroundColor ||
+                                      componentRawStyles[@"weexLightSchemeBackgroundColor"] != nil)) {
+                continue;
+            }
+        }
+        else if ([property isEqualToString:@"weexDarkSchemeBackgroundColor"]) {
+            if (!isDarkScheme || componentRawStyles[@"weexDarkSchemeBackgroundColor"] == nil) {
+                /* Do not do animation for "darkSchemeBackgroundColor" in light mode.
+                 Or there is no dark bg color explicitly defined in styles.
+                 */
+                continue;
+            }
+        }
+        else if ([property isEqualToString:@"weexLightSchemeBackgroundColor"]){
+            if (isDarkScheme || componentRawStyles[@"weexLightSchemeBackgroundColor"] == nil) {
+                continue;
+            }
+        }
+        
         WXAnimationInfo *info = [WXAnimationInfo new];
         info.duration = duration;
         info.delay = delay;
@@ -287,10 +321,18 @@
                 [infos addObject:newInfo];
             }
             target.transform = wxTransform;
-        } else if ([property isEqualToString:@"backgroundColor"]) {
+        } else if ([property isEqualToString:@"backgroundColor"] ||
+                   [property isEqualToString:@"weexDarkSchemeBackgroundColor"] ||
+                   [property isEqualToString:@"weexLightSchemeBackgroundColor"]) {
             info.propertyName = @"backgroundColor";
             info.fromValue = (__bridge id)(layer.backgroundColor);
-            info.toValue = (__bridge id)[WXConvert CGColor:value];
+            UIColor* toColor = [WXConvert UIColor:value];
+            if ([target.weexInstance isDarkScheme] && target.invertForDarkScheme &&
+                [property isEqualToString:@"backgroundColor"]) {
+                // Invert color
+                toColor = [[WXSDKInstance darkSchemeColorHandler] getInvertedColorFor:toColor ofScene:[target colorSceneType] withDefault:toColor];
+            }
+            info.toValue = (__bridge id)([toColor CGColor]);
             [infos addObject:info];
         } else if ([property isEqualToString:@"opacity"]) {
             info.propertyName = @"opacity";
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m b/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m
index e6c158f..2a50189 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m
@@ -77,7 +77,6 @@
 
 @implementation WXTimerModule
 {
-    BOOL _tooManyTimersReported;
     NSMutableDictionary *_timers;
 }
 
@@ -162,6 +161,12 @@
 
 - (void)createTimerWithCallback:(NSString *)callbackID time:(NSTimeInterval)milliseconds target:(id)target selector:(SEL)selector shouldRepeat:(BOOL)shouldRepeat {
     
+    WXAssert(!isnan(milliseconds), @"Timer interval is NAN.");
+    if (isnan(milliseconds)) { //!OCLint
+        WXLogError(@"Create timer with NAN interval.");
+        return;
+    }
+    
     NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:milliseconds/1000.0f target:target selector:selector userInfo:nil repeats:shouldRepeat];
     [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
     
@@ -178,14 +183,6 @@
                 }
             }
             [_timers removeObjectsForKeys:invalidTimerIds];
-            
-            // If alive timer count still exceeds 30, we report once for this page.
-            if ([_timers count] > 30) {
-                if (!_tooManyTimersReported) {
-                    [WXExceptionUtils commitCriticalExceptionRT:self.weexInstance.instanceId errCode:[NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_TOO_MANY_TIMERS] function:@"" exception:@"Too many timers." extParams:nil];
-                    _tooManyTimersReported = YES;
-                }
-            }
         }
     }
 }
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm b/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm
index 8bb616d..e52c5ba 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm
+++ b/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm
@@ -30,6 +30,7 @@
 #import "WXAssert.h"
 #import "WXSDKInstance_private.h"
 #import "WXLength.h"
+#import "WXDarkSchemeProtocol.h"
 
 @implementation WXTransitionInfo
 @end
@@ -82,6 +83,8 @@
                                                            @"bottom": @(WXTransitionOptionsBottom),
                                                            @"top": @(WXTransitionOptionsTop),
                                                            @"backgroundColor": @(WXTransitionOptionsBackgroundColor),
+                                                           @"weexDarkSchemeBackgroundColor": @(WXTransitionOptionsBackgroundColor),
+                                                           @"weexLightSchemeBackgroundColor": @(WXTransitionOptionsBackgroundColor),
                                                            @"transform": @(WXTransitionOptionsTransform),
                                                            @"opacity": @(WXTransitionOptionsOpacity)
                                                            };
@@ -106,24 +109,68 @@
     _filterStyles = _filterStyles ?:[NSMutableDictionary new];
     _oldFilterStyles = _oldFilterStyles ?: [NSMutableDictionary new];
     NSMutableDictionary *futileStyles = [NSMutableDictionary new];
+    NSDictionary* componentRawStyles = targetComponent.styles;
+    
+    BOOL isDarkScheme = [targetComponent.weexInstance isDarkScheme];
+    BOOL updatingDarkSchemeBackgroundColor = styles[@"weexDarkSchemeBackgroundColor"] != nil;
+    BOOL updatingLightSchemeBackgroundColor = styles[@"weexLightSchemeBackgroundColor"] != nil;
     
     for (NSString *key in styles) {
         if (self.transitionOptions & [self transitionOptionsFromString:key]) {
+            if ([key isEqualToString:@"backgroundColor"]) {
+                if (isDarkScheme && (updatingDarkSchemeBackgroundColor ||
+                                    componentRawStyles[@"weexDarkSchemeBackgroundColor"] != nil)) {
+                    /* Updating "darkSchemeBackgroundColor" in dark mode,
+                     or this component has dark bg color explicitly defined in styels.
+                     We ignore transition animation for "backgroundColor" */
+                    [futileStyles setObject:styles[key] forKey:key];
+                    continue;
+                }
+                else if (!isDarkScheme && (updatingLightSchemeBackgroundColor ||
+                                          componentRawStyles[@"weexLightSchemeBackgroundColor"] != nil)) {
+                    [futileStyles setObject:styles[key] forKey:key];
+                    continue;
+                }
+            }
+            else if ([key isEqualToString:@"weexDarkSchemeBackgroundColor"]) {
+                if (!isDarkScheme || componentRawStyles[@"weexDarkSchemeBackgroundColor"] == nil) {
+                    /* Do not do animation for "darkSchemeBackgroundColor" in light mode.
+                     Or there is no dark bg color explicitly defined in styles.
+                     */
+                    [futileStyles setObject:styles[key] forKey:key];
+                    continue;
+                }
+            }
+            else if ([key isEqualToString:@"weexLightSchemeBackgroundColor"]){
+                if (isDarkScheme || componentRawStyles[@"weexLightSchemeBackgroundColor"] == nil) {
+                    [futileStyles setObject:styles[key] forKey:key];
+                    continue;
+                }
+            }
+            
             [_filterStyles setObject:styles[key] forKey:key];
             if (![key isEqualToString:@"transform"]) {
                 if (!isRunning) {
-                    /* style value may not be in component.styles, so we must get
-                     value from layout and convert it to style value. */
-                    id styleValue = targetComponent.styles[key];
-                    if (styleValue == nil) {
+                    // Get animation 'from' value from raw styles.
+                    id styleValue = componentRawStyles[key];
+                    if ([key isEqualToString:@"backgroundColor"] ||
+                        [key isEqualToString:@"weexDarkSchemeBackgroundColor"] ||
+                        [key isEqualToString:@"weexLightSchemeBackgroundColor"]) {
+                        if (styleValue == nil) {
+                            // background color is transparent by default.
+                            styleValue = @"transparent";
+                        }
+                    }
+                    else if (styleValue == nil) {
+                        /* Flex styles may not be in component.styles, so we must get
+                         value from layout and convert it to style value. */
                         styleValue = [targetComponent convertLayoutValueToStyleValue:key];
                     }
                     [_oldFilterStyles setObject:styleValue forKey:key];
                 }
             }
         }
-        else
-        {
+        else {
             [futileStyles setObject:styles[key] forKey:key];
         }
     }
@@ -131,7 +178,7 @@
 
     _targetComponent = targetComponent;
     NSMutableDictionary *componentStyles = [NSMutableDictionary dictionaryWithDictionary:styles];
-    [componentStyles addEntriesFromDictionary:targetComponent.styles];
+    [componentStyles addEntriesFromDictionary:componentRawStyles];
 
     _transitionDuration = componentStyles[kWXTransitionDuration] ? [WXConvert CGFloat:componentStyles[kWXTransitionDuration]] : 0;
     _transitionDelay = componentStyles[kWXTransitionDelay] ? [WXConvert CGFloat:componentStyles[kWXTransitionDelay]] : 0;
@@ -200,10 +247,22 @@
         if (!_propertyArray) {
             _propertyArray = [NSMutableArray new];
         }
-        if ([singleProperty isEqualToString:@"backgroundColor"]) {
+        if ([singleProperty isEqualToString:@"backgroundColor"] ||
+            [singleProperty isEqualToString:@"weexDarkSchemeBackgroundColor"] ||
+            [singleProperty isEqualToString:@"weexLightSchemeBackgroundColor"]) {
+            UIColor* fromColor = [WXConvert UIColor:_oldFilterStyles[singleProperty]];
+            UIColor* toColor = [WXConvert UIColor:_filterStyles[singleProperty]];
+            if ([_targetComponent.weexInstance isDarkScheme] &&
+                _targetComponent.invertForDarkScheme &&
+                [singleProperty isEqualToString:@"backgroundColor"]) {
+                // Invert color
+                fromColor = [[WXSDKInstance darkSchemeColorHandler] getInvertedColorFor:fromColor ofScene:[_targetComponent colorSceneType] withDefault:fromColor];
+                toColor = [[WXSDKInstance darkSchemeColorHandler] getInvertedColorFor:toColor ofScene:[_targetComponent colorSceneType] withDefault:toColor];
+            }
+            
             WXTransitionInfo *info = [WXTransitionInfo new];
-            info.fromValue = [self _dealWithColor:[WXConvert UIColor:_oldFilterStyles[singleProperty]]];
-            info.toValue = [self _dealWithColor:[WXConvert UIColor:_filterStyles[singleProperty]]];
+            info.fromValue = [self _dealWithColor:fromColor];
+            info.toValue = [self _dealWithColor:toColor];
             info.perValue = [self _calculatePerColorRGB1:info.toValue RGB2:info.fromValue];
             info.propertyName = singleProperty;
             [_propertyArray addObject:info];
@@ -337,6 +396,7 @@
                                @([info.fromValue[3] floatValue] + [info.perValue[3] floatValue] * per)];
             UIColor *color = [UIColor colorWithRed:[array[0] floatValue] green:[array[1] floatValue] blue:[array[2] floatValue] alpha:[array[3] floatValue]];
             WXPerformBlockOnMainThread(^{
+                // Here we do not need to consider about dark mode.
                 _targetComponent.view.backgroundColor = color;
                 [_targetComponent.view setNeedsDisplay];
             });
diff --git a/ios/sdk/WeexSDK/Sources/Protocol/WXDarkSchemeProtocol.h b/ios/sdk/WeexSDK/Sources/Protocol/WXDarkSchemeProtocol.h
new file mode 100644
index 0000000..0689bd4
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Protocol/WXDarkSchemeProtocol.h
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <WeexSDK/WXModuleProtocol.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol WXDarkSchemeProtocol <WXModuleProtocol>
+
+/**
+ Return YES so that Weex root component will be enabled for 'invertForDarkScheme' property.
+*/
+- (BOOL)defaultInvertValueForRootComponent;
+
+/**
+After any view of Weex component is created. Callback dark scheme handler to provide a
+ chance to configure the view.
+*/
+- (void)configureView:(UIView*_Nonnull)view ofComponent:(WXComponent*_Nonnull)component;
+
+/**
+ Get inverted color in dark mode for input color with scene hint.
+
+ @param color Input color.
+ @param scene Scene indicating the color usage.
+ @param defaultColor If no inverted one matches, return the default color.
+ @return Inverted color.
+ */
+- (UIColor *_Nullable)getInvertedColorFor:(UIColor *_Nonnull)color ofScene:(WXColorScene)scene withDefault:(UIColor *_Nullable)defaultColor;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ios/sdk/WeexSDK/Sources/Protocol/WXDestroyProtocol.h b/ios/sdk/WeexSDK/Sources/Protocol/WXDestroyProtocol.h
deleted file mode 100644
index 1875e79..0000000
--- a/ios/sdk/WeexSDK/Sources/Protocol/WXDestroyProtocol.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 <Foundation/Foundation.h>
-
-@protocol WXDestroyProtocol <NSObject>
-
-/**
- *  @abstract execute unload function before dealloc
- */
-- (void)unload;
-
-@end
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h
index a5e64f5..2cd8f9b 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h
@@ -47,6 +47,14 @@
 
 void ConvertToCString(id _Nonnull obj, void (^ _Nonnull callback)(const char* _Nullable));
 
+extern "C" {
+    void SetConvertCurrentPage(NSString* _Nonnull pageId);
+    void ConvertSwitches(BOOL isIOS13, BOOL invalidJSONObjectUseMRC, BOOL alwaysUseMRC);
+}
+
+#else
+void SetConvertCurrentPage(NSString* _Nonnull pageId);
+void ConvertSwitches(BOOL isIOS13, BOOL invalidJSONObjectUseMRC, BOOL alwaysUseMRC);
 #endif
 
 #endif
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm
index bec9105..65d035d 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm
@@ -20,10 +20,32 @@
 #import "WXConvertUtility.h"
 #import "WXLog.h"
 #import "WXAssert.h"
+#import "WXExceptionUtils.h"
+#import "WXSDKError.h"
+
 #include <vector>
 #include <string>
 
 static NSString* const JSONSTRING_SUFFIX = @"\t\n\t\r";
+static NSString* const OBJC_MRC_SUFFIX = @"\t\t\n\r";
+
+static BOOL bIsIOS13 = NO;
+static BOOL bUseMRCForInvalidJSONObject = NO;
+static BOOL bAlwaysUseMRC = NO;
+
+static NSString* sCurrentPage = nil;
+
+void SetConvertCurrentPage(NSString* pageId)
+{
+    sCurrentPage = pageId;
+}
+
+void ConvertSwitches(BOOL isIOS13, BOOL invalidJSONObjectUseMRC, BOOL alwaysUseMRC)
+{
+    bIsIOS13 = isIOS13;
+    bUseMRCForInvalidJSONObject = invalidJSONObjectUseMRC;
+    bAlwaysUseMRC = alwaysUseMRC;
+}
 
 #if 0
 
@@ -78,6 +100,28 @@
             _detectObjectRecursion(object, nodes);
 #endif
             
+            if (bAlwaysUseMRC) {
+                return [NSString stringWithFormat:@"%p%@", (__bridge_retained void*)object, OBJC_MRC_SUFFIX];
+            }
+            
+            if (bIsIOS13) {
+                if (![NSJSONSerialization isValidJSONObject:object]) {
+                    [WXExceptionUtils commitCriticalExceptionRT:sCurrentPage
+                                                        errCode:[NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_INVALID_JSON_OBJECT]
+                                                       function:@""
+                                                      exception:@"Invalid JSON object."
+                                                      extParams:nil];
+                    
+                    // Report for instance.
+                    if (bUseMRCForInvalidJSONObject) {
+                        return [NSString stringWithFormat:@"%p%@", (__bridge_retained void*)object, OBJC_MRC_SUFFIX];
+                    }
+                    else {
+                        return nil;
+                    }
+                }
+            }
+            
             NSError *error = nil;
             NSData *data = [NSJSONSerialization dataWithJSONObject:object
                                                            options:0
@@ -126,6 +170,15 @@
             WXAssert(NO, @"Fail to convert json to object. %@", exception);
         }
     }
+    else if ([s hasSuffix:OBJC_MRC_SUFFIX]) {
+        NSScanner* scanner = [NSScanner scannerWithString:s];
+        unsigned long long address = 0;
+        [scanner scanHexLongLong:&address];
+        if (address != 0) {
+            return (__bridge_transfer id)((void*)address);
+        }
+    }
+    
     return s; // return s instead
 }
 
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXDefine.h b/ios/sdk/WeexSDK/Sources/Utility/WXDefine.h
index a9b9dcf..c687ab0 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXDefine.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXDefine.h
@@ -20,7 +20,7 @@
 #ifndef __WX_DEFINE_H__
 #define __WX_DEFINE_H__
 
-#define WX_SDK_VERSION @"0.24.0"
+#define WX_SDK_VERSION @"0.28.0"
 
 #if defined(__cplusplus)
 #define WX_EXTERN extern "C" __attribute__((visibility("default")))
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
index 61eeccd..49d2d71 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
@@ -131,6 +131,14 @@
 + (void)performBlock:(void (^_Nonnull)(void))block onThread:(NSThread *_Nonnull)thread;
 
 /**
+ * @abstract Check if system is in dark mode.
+ *
+ * @return Boolean
+ *
+ */
++ (BOOL)isSystemInDarkScheme;
+
+/**
  * @abstract Returns the environment of current application, you can get some necessary properties such as appVersion、sdkVersion、appName etc.
  *
  * @return A dictionary object which contains these properties.
@@ -502,10 +510,20 @@
  */
 + (NSData *_Nonnull)base64DictToData:(NSDictionary *_Nullable)base64Dict;
 
+/**
+*  @abstract Switch for RTL.
+*
+*/
 + (void)setEnableRTLLayoutDirection:(BOOL)value;
-
 + (BOOL)enableRTLLayoutDirection;
 
+/**
+*  @abstract Switch for dark mode support.
+*
+*/
++ (void)setDarkSchemeSupportEnable:(BOOL)value;
++ (BOOL)isDarkSchemeSupportEnabled;
+
 + (long) getUnixFixTimeMillis;
 
 + (NSArray<NSString *> *_Nullable)extractPropertyNamesOfJSValueObject:(JSValue *_Nullable)jsvalue;
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
index 6ec4223..12d4911 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
@@ -43,6 +43,7 @@
 #define KEY_USERNAME_PASSWORD  @"com.taobao.Weex.weex123456"
 
 static BOOL enableRTLLayoutDirection = YES;
+static BOOL isDarkSchemeSupportEnabled = YES;
 
 void WXPerformBlockOnMainThread(void (^ _Nonnull block)(void))
 {
@@ -163,8 +164,29 @@
     return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:UISemanticContentAttributeUnspecified] == UIUserInterfaceLayoutDirectionRightToLeft ? WXLayoutDirectionRTL : WXLayoutDirectionLTR;
 }
 
++ (BOOL)isSystemInDarkScheme
+{
+    if (@available(iOS 13.0, *)) {
+        __block BOOL result = NO;
+        WXPerformBlockSyncOnMainThread(^{
+#ifdef __IPHONE_13_0
+            if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) {
+                result = YES;
+            }
+#endif
+        });
+        return result;
+    }
+    return NO;
+}
+
 + (NSDictionary *)getEnvironment
 {
+    NSString* currentScheme = @"light";
+    if ([WXUtility isDarkSchemeSupportEnabled]) {
+        currentScheme = [self isSystemInDarkScheme] ? @"dark" : @"light";
+    }
+    
     NSString *platform = @"iOS";
     NSString *sysVersion = [[UIDevice currentDevice] systemVersion] ?: @"";
     NSString *weexVersion = WX_SDK_VERSION;
@@ -187,7 +209,8 @@
                                     @"deviceWidth":@(deviceWidth * scale),
                                     @"deviceHeight":@(deviceHeight * scale),
                                     @"scale":@(scale),
-                                    @"layoutDirection": [self getEnvLayoutDirection] == WXLayoutDirectionRTL ? @"rtl" : @"ltr"
+                                    @"layoutDirection": [self getEnvLayoutDirection] == WXLayoutDirectionRTL ? @"rtl" : @"ltr",
+                                    @"scheme": currentScheme
                                 }];
     
     if ([[[UIDevice currentDevice] systemVersion] integerValue] >= 11) {
@@ -793,6 +816,18 @@
     return enableRTLLayoutDirection;
 }
 
+#pragma mark - Dark scheme
+
++ (void)setDarkSchemeSupportEnable:(BOOL)value
+{
+    isDarkSchemeSupportEnabled = value;
+}
+
++ (BOOL)isDarkSchemeSupportEnabled
+{
+    return isDarkSchemeSupportEnabled;
+}
+
 #pragma mark - get deviceID
 + (NSString *)getDeviceID {
     NSMutableDictionary *usernamepasswordKVPairs = (NSMutableDictionary *)[self load:KEY_USERNAME_PASSWORD];
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXVersion.m b/ios/sdk/WeexSDK/Sources/Utility/WXVersion.m
index b283b3a..002b48b 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXVersion.m
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXVersion.m
@@ -1,29 +1,27 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
+* Licensed to the Apache Software Foundation (ASF) under one 
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you 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 "WXVersion.h"
 #import "WXDefine.h"
 
-
-static const char* WeexSDKBuildTime = "2019-08-26 08:28:24 UTC";
-static const unsigned long WeexSDKBuildTimestamp = 1566808104;
-
+static const char* WeexSDKBuildTime = "2019-10-09 13:07:35 UTC";
+static const unsigned long WeexSDKBuildTimestamp = 1570626455;
 
 NSString* GetWeexSDKVersion(void)
 {
diff --git a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
index 3d97548..4d058ef 100644
--- a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
+++ b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
@@ -67,6 +67,22 @@
     }\
 } while(0);
 
+#define WX_BOARD_RADIUS_DARK_SCHEME_COLOR_RESET_ALL(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _darkSchemeBorderTopColor = _darkSchemeBorderLeftColor = _darkSchemeBorderRightColor = _darkSchemeBorderBottomColor = [UIColor blackColor];\
+        [self setNeedsDisplay];\
+    }\
+} while(0);
+
+#define WX_BOARD_RADIUS_LIGHT_SCHEME_COLOR_RESET_ALL(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _lightSchemeBorderTopColor = _lightSchemeBorderLeftColor = _lightSchemeBorderRightColor = _lightSchemeBorderBottomColor = [UIColor blackColor];\
+        [self setNeedsDisplay];\
+    }\
+} while(0);
+
 #define WX_BOARD_COLOR_RESET(key)\
 do {\
     if (styles && [styles containsObject:@#key]) {\
@@ -174,8 +190,16 @@
 
 - (void)_initViewPropertyWithStyles:(NSDictionary *)styles
 {
-    _backgroundColor = styles[@"backgroundColor"] ? [WXConvert UIColor:styles[@"backgroundColor"]] : [UIColor clearColor];
+    self.styleBackgroundColor = styles[@"backgroundColor"] ? [WXConvert UIColor:styles[@"backgroundColor"]] : [UIColor clearColor];
+    if (styles[@"weexDarkSchemeBackgroundColor"]) {
+        self.darkSchemeBackgroundColor = [WXConvert UIColor:styles[@"weexDarkSchemeBackgroundColor"]];
+    }
+    if (styles[@"weexLightSchemeBackgroundColor"]) {
+        self.lightSchemeBackgroundColor = [WXConvert UIColor:styles[@"weexLightSchemeBackgroundColor"]];
+    }
     _backgroundImage = styles[@"backgroundImage"] ? [WXConvert NSString:styles[@"backgroundImage"]]: nil;
+    _darkSchemeBackgroundImage = styles[@"weexDarkSchemeBackgroundImage"] ? [WXConvert NSString:styles[@"weexDarkSchemeBackgroundImage"]] : nil;
+    _lightSchemeBackgroundImage = styles[@"weexLightSchemeBackgroundImage"] ? [WXConvert NSString:styles[@"weexLightSchemeBackgroundImage"]] : nil;
     _opacity = styles[@"opacity"] ? [WXConvert CGFloat:styles[@"opacity"]] : 1.0;
     _clipToBounds = styles[@"overflow"] ? [WXConvert WXClipType:styles[@"overflow"]] : NO;
     _visibility = styles[@"visibility"] ? [WXConvert WXVisibility:styles[@"visibility"]] : WXVisibilityShow;
@@ -184,8 +208,11 @@
     [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:[WXConvert NSString:styles[@"transformOrigin"]] instance:self.weexInstance] :
     [[WXTransform alloc] initWithCSSValue:nil origin:nil instance:self.weexInstance];
     _boxShadow = styles[@"boxShadow"]?[WXConvert WXBoxShadow:styles[@"boxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor]:nil;
-    if (_boxShadow) {
-        _lastBoxShadow = _boxShadow;
+    if (styles[@"weexDarkSchemeBoxShadow"]) {
+        _darkSchemeBoxShadow = [WXConvert WXBoxShadow:styles[@"weexDarkSchemeBoxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor];
+    }
+    if (styles[@"weexLightSchemeBoxShadow"]) {
+        _lightSchemeBoxShadow = [WXConvert WXBoxShadow:styles[@"weexLightSchemeBoxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor];
     }
 }
 
@@ -193,7 +220,13 @@
 {
     WX_CHECK_COMPONENT_TYPE(self.componentType)
     if (styles[@"backgroundColor"]) {
-        _backgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
+        self.styleBackgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
+    }
+    if (styles[@"weexDarkSchemeBackgroundColor"]) {
+        self.darkSchemeBackgroundColor = [WXConvert UIColor:styles[@"weexDarkSchemeBackgroundColor"]];
+    }
+    if (styles[@"weexLightSchemeBackgroundColor"]) {
+        self.lightSchemeBackgroundColor = [WXConvert UIColor:styles[@"weexLightSchemeBackgroundColor"]];
     }
     if (styles[@"opacity"]) {
         _opacity = [WXConvert CGFloat:styles[@"opacity"]];
@@ -204,20 +237,53 @@
 {
     WX_CHECK_COMPONENT_TYPE(self.componentType)
     if (styles[@"boxShadow"]) {
-        _lastBoxShadow = _boxShadow;
         _boxShadow = styles[@"boxShadow"]?[WXConvert WXBoxShadow:styles[@"boxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor]:nil;
-        [self configBoxShadow:_boxShadow];
+    }
+    if (styles[@"weexDarkSchemeBoxShadow"]) {
+        _darkSchemeBoxShadow = [WXConvert WXBoxShadow:styles[@"weexDarkSchemeBoxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor];
+    }
+    if (styles[@"weexLightSchemeBoxShadow"]) {
+        _lightSchemeBoxShadow = [WXConvert WXBoxShadow:styles[@"weexLightSchemeBoxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor];
+    }
+    if (styles[@"boxShadow"] || styles[@"weexDarkSchemeBoxShadow"] || styles[@"weexLightSchemeBoxShadow"]) {
+        WXBoxShadow* usingBoxShadow = [self _chooseBoxShadow];
+        if (usingBoxShadow) {
+            _lastBoxShadow = usingBoxShadow;
+            [self configBoxShadow:usingBoxShadow];
+        }
         [self setNeedsDisplay];
     }
     
     if (styles[@"backgroundColor"]) {
-        _backgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
+        self.styleBackgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
+        [self setNeedsDisplay];
+    }
+    
+    if (styles[@"weexDarkSchemeBackgroundColor"]) {
+        self.darkSchemeBackgroundColor = [WXConvert UIColor:styles[@"weexDarkSchemeBackgroundColor"]];
+        [self setNeedsDisplay];
+    }
+    
+    if (styles[@"weexLightSchemeBackgroundColor"]) {
+        self.lightSchemeBackgroundColor = [WXConvert UIColor:styles[@"weexLightSchemeBackgroundColor"]];
         [self setNeedsDisplay];
     }
     
     if (styles[@"backgroundImage"]) {
-        _backgroundImage = styles[@"backgroundImage"] ? [WXConvert NSString:styles[@"backgroundImage"]]: nil;
-        if (_backgroundImage) {
+        _backgroundImage = [WXConvert NSString:styles[@"backgroundImage"]];
+    }
+    
+    if (styles[@"weexDarkSchemeBackgroundImage"]) {
+        _darkSchemeBackgroundImage = [WXConvert NSString:styles[@"weexDarkSchemeBackgroundImage"]];
+    }
+    if (styles[@"weexLightSchemeBackgroundImage"]) {
+        _lightSchemeBackgroundImage = [WXConvert NSString:styles[@"weexLightSchemeBackgroundImage"]];
+    }
+    
+    if (styles[@"backgroundImage"] ||
+        styles[@"weexDarkSchemeBackgroundImage"] ||
+        styles[@"weexLightSchemeBackgroundImage"]) {
+        if (_backgroundImage || _darkSchemeBackgroundImage || _lightSchemeBackgroundImage) {
             [self setGradientLayer];
         }
     }
@@ -302,21 +368,61 @@
     WX_BOARD_COLOR_RESET(borderLeftColor);
     WX_BOARD_COLOR_RESET(borderRightColor);
     WX_BOARD_COLOR_RESET(borderBottomColor);
+    
+    WX_BOARD_RADIUS_DARK_SCHEME_COLOR_RESET_ALL(darkSchemeBorderColor);
+    WX_BOARD_COLOR_RESET(darkSchemeBorderTopColor);
+    WX_BOARD_COLOR_RESET(darkSchemeBorderLeftColor);
+    WX_BOARD_COLOR_RESET(darkSchemeBorderRightColor);
+    WX_BOARD_COLOR_RESET(darkSchemeBorderBottomColor);
+    
+    WX_BOARD_RADIUS_LIGHT_SCHEME_COLOR_RESET_ALL(lightSchemeBorderColor);
+    WX_BOARD_COLOR_RESET(lightSchemeBorderTopColor);
+    WX_BOARD_COLOR_RESET(lightSchemeBorderLeftColor);
+    WX_BOARD_COLOR_RESET(lightSchemeBorderRightColor);
+    WX_BOARD_COLOR_RESET(lightSchemeBorderBottomColor);
 }
 
 - (void)_resetStyles:(NSArray *)styles
 {
     if (styles && [styles containsObject:@"backgroundColor"]) {
-        _backgroundColor = [UIColor clearColor];
+        self.styleBackgroundColor = [UIColor clearColor];
         [self setNeedsDisplay];
     }
+    if (styles && [styles containsObject:@"weexDarkSchemeBackgroundColor"]) {
+        self.darkSchemeBackgroundColor = nil;
+        [self setNeedsDisplay];
+    }
+    if (styles && [styles containsObject:@"weexLightSchemeBackgroundColor"]) {
+        self.lightSchemeBackgroundColor = nil;
+        [self setNeedsDisplay];
+    }
+    
     if (styles && [styles containsObject:@"boxShadow"]) {
         _lastBoxShadow = _boxShadow;
         _boxShadow = nil;
         [self setNeedsDisplay];
     }
+    if (styles && [styles containsObject:@"weexDarkSchemeBoxShadow"]) {
+        _darkSchemeBoxShadow = nil;
+        [self setNeedsDisplay];
+    }
+    if (styles && [styles containsObject:@"weexLightSchemeBoxShadow"]) {
+        _lightSchemeBoxShadow = nil;
+        [self setNeedsDisplay];
+    }
+    
     if (styles && [styles containsObject:@"backgroundImage"]) {
         _backgroundImage = nil;
+    }
+    if (styles && [styles containsObject:@"weexDarkSchemeBackgroundImage"]) {
+        _darkSchemeBackgroundImage = nil;
+    }
+    if (styles && [styles containsObject:@"weexLightSchemeBackgroundImage"]) {
+        _lightSchemeBackgroundImage = nil;
+    }
+    if (styles && ([styles containsObject:@"backgroundImage"] ||
+                   [styles containsObject:@"weexDarkSchemeBackgroundImage"] ||
+                   [styles containsObject:@"weexLightSchemeBackgroundImage"])) {
         [self setGradientLayer];
     }
     
diff --git a/ios/sdk/WeexSDK/Sources/View/WXRootView.m b/ios/sdk/WeexSDK/Sources/View/WXRootView.m
index 3cc8a36..0df4760 100644
--- a/ios/sdk/WeexSDK/Sources/View/WXRootView.m
+++ b/ios/sdk/WeexSDK/Sources/View/WXRootView.m
@@ -23,6 +23,10 @@
 #import "WXSDKEngine.h"
 
 @interface WXRootView()
+{
+    BOOL _hasFirstTraitCollectionChange;
+    BOOL _allowFirstTraitCollectionChange;
+}
 
 @property (nonatomic, assign) BOOL mHasEvent;
 
@@ -59,4 +63,36 @@
     return _mHasEvent;
 }
 
+- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
+{
+    [super traitCollectionDidChange:previousTraitCollection];
+    
+    if (@available(iOS 13.0, *)) {
+        // When entering background system may call back change twice.. We ignore the first one.
+        UIUserInterfaceStyle currentStyle = self.traitCollection.userInterfaceStyle;
+        if (currentStyle != previousTraitCollection.userInterfaceStyle) {
+            if (_hasFirstTraitCollectionChange) {
+                _allowFirstTraitCollectionChange = NO;
+                [self.instance setCurrentSchemeName:currentStyle == UIUserInterfaceStyleDark ? @"dark" : @"light"];
+            }
+            else {
+                __weak WXRootView* weakSelf = self;
+                _hasFirstTraitCollectionChange = YES;
+                _allowFirstTraitCollectionChange = YES;
+                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+                    __strong WXRootView* strongSelf = weakSelf;
+                    if (strongSelf) {
+                        if (strongSelf->_allowFirstTraitCollectionChange) {
+                            if (strongSelf.instance) {
+                                [strongSelf.instance setCurrentSchemeName:currentStyle == UIUserInterfaceStyleDark ? @"dark" : @"light"];
+                            }
+                        }
+                        strongSelf->_hasFirstTraitCollectionChange = NO;
+                    }
+                });
+            }
+        }
+    }
+}
+
 @end
diff --git a/ios/sdk/WeexSDK/Sources/WeexSDK.h b/ios/sdk/WeexSDK/Sources/WeexSDK.h
index 8e5f6f4..05807f0 100644
--- a/ios/sdk/WeexSDK/Sources/WeexSDK.h
+++ b/ios/sdk/WeexSDK/Sources/WeexSDK.h
@@ -73,6 +73,7 @@
 #import <WeexSDK/WXDefine.h>
 #import <WeexSDK/WXDebugTool.h>
 #import <WeexSDK/WXDataRenderHandler.h>
+#import <WeexSDK/WXDarkSchemeProtocol.h>
 #import <WeexSDK/WXConvertUtility.h>
 #import <WeexSDK/WXConvert.h>
 #import <WeexSDK/WXConfigCenterProtocol.h>
diff --git a/package-lock.json b/package-lock.json
index a16a0f3..3d9777a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,11 +4,121 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "@babel/polyfill": {
+      "version": "7.6.0",
+      "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.6.0.tgz",
+      "integrity": "sha512-q5BZJI0n/B10VaQQvln1IlDK3BTBJFbADx7tv+oXDPIDZuTo37H5Adb9jhlXm/fEN4Y7/64qD9mnrJJG7rmaTw==",
+      "dev": true,
+      "requires": {
+        "core-js": "^2.6.5",
+        "regenerator-runtime": "^0.13.2"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "2.6.10",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
+          "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==",
+          "dev": true
+        },
+        "regenerator-runtime": {
+          "version": "0.13.3",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
+          "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==",
+          "dev": true
+        }
+      }
+    },
+    "@octokit/endpoint": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.0.tgz",
+      "integrity": "sha512-TXYS6zXeBImNB9BVj+LneMDqXX+H0exkOpyXobvp92O3B1348QsKnNioISFKgOMsb3ibZvQGwCdpiwQd3KAjIA==",
+      "dev": true,
+      "requires": {
+        "@octokit/types": "^1.0.0",
+        "is-plain-object": "^3.0.0",
+        "universal-user-agent": "^4.0.0"
+      }
+    },
+    "@octokit/request": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.0.tgz",
+      "integrity": "sha512-mMIeNrtYyNEIYNsKivDyUAukBkw0M5ckyJX56xoFRXSasDPCloIXaQOnaKNopzQ8dIOvpdq1ma8gmrS+h6O2OQ==",
+      "dev": true,
+      "requires": {
+        "@octokit/endpoint": "^5.5.0",
+        "@octokit/request-error": "^1.0.1",
+        "@octokit/types": "^1.0.0",
+        "deprecation": "^2.0.0",
+        "is-plain-object": "^3.0.0",
+        "node-fetch": "^2.3.0",
+        "once": "^1.4.0",
+        "universal-user-agent": "^4.0.0"
+      },
+      "dependencies": {
+        "node-fetch": {
+          "version": "2.6.0",
+          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
+          "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
+          "dev": true
+        }
+      }
+    },
+    "@octokit/request-error": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.0.4.tgz",
+      "integrity": "sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==",
+      "dev": true,
+      "requires": {
+        "deprecation": "^2.0.0",
+        "once": "^1.4.0"
+      }
+    },
+    "@octokit/rest": {
+      "version": "16.34.1",
+      "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.34.1.tgz",
+      "integrity": "sha512-JUoS12cdktf1fv86rgrjC/RvYLuL+o7p57W7zX1x7ANFJ7OvdV8emvUNkFlcidEaOkYrxK3SoWgQFt3FhNmabA==",
+      "dev": true,
+      "requires": {
+        "@octokit/request": "^5.2.0",
+        "@octokit/request-error": "^1.0.2",
+        "atob-lite": "^2.0.0",
+        "before-after-hook": "^2.0.0",
+        "btoa-lite": "^1.0.0",
+        "deprecation": "^2.0.0",
+        "lodash.get": "^4.4.2",
+        "lodash.set": "^4.3.2",
+        "lodash.uniq": "^4.5.0",
+        "octokit-pagination-methods": "^1.1.0",
+        "once": "^1.4.0",
+        "universal-user-agent": "^4.0.0"
+      }
+    },
+    "@octokit/types": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-1.1.0.tgz",
+      "integrity": "sha512-t4ZD74UnNVMq6kZBDZceflRKK3q4o5PoCKMAGht0RK84W57tqonqKL3vCxJHtbGExdan9RwV8r7VJBZxIM1O7Q==",
+      "dev": true,
+      "requires": {
+        "@types/node": "^12.11.1"
+      }
+    },
+    "@types/node": {
+      "version": "12.12.3",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.3.tgz",
+      "integrity": "sha512-opgSsy+cEF9N8MgaVPnWVtdJ3o4mV2aMHvDq7thkQUFt0EuOHJon4rQpJfhjmNHB+ikl0Cd6WhWIErOyQ+f7tw==",
+      "dev": true
+    },
     "@weex-project/downgrade": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@weex-project/downgrade/-/downgrade-1.1.0.tgz",
       "integrity": "sha512-hMWmH/k4xL8f4BPWPi+Bi4p+ufn2xR4cgqGQcjof/CMZHWFATjSPeQmNzjVFz3zUTSt3iXlE482KDrIKaGpjsw=="
     },
+    "@zeit/schemas": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-1.1.2.tgz",
+      "integrity": "sha512-1KCchM412X/6h1b5XAU3CUe2Teu7duHa6ECkQVa27PmD4UWzciB3oAlElDv4uqAKJFfwprG1eeqwjtmGIQcJcg==",
+      "dev": true
+    },
     "JSONStream": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.3.tgz",
@@ -19,23 +129,28 @@
         "through": ">=2.2.7 <3"
       }
     },
-    "abab": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
-      "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=",
-      "dev": true
-    },
     "abbrev": {
       "version": "1.0.9",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
       "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=",
       "dev": true
     },
-    "acorn": {
-      "version": "4.0.13",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
-      "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
-      "dev": true
+    "abort-controller": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+      "dev": true,
+      "requires": {
+        "event-target-shim": "^5.0.0"
+      },
+      "dependencies": {
+        "event-target-shim": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+          "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+          "dev": true
+        }
+      }
     },
     "acorn-dynamic-import": {
       "version": "3.0.0",
@@ -60,15 +175,6 @@
       "integrity": "sha1-zGyYKYkfmpduMn+CM7B6sBV9iVo=",
       "dev": true
     },
-    "acorn-globals": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz",
-      "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=",
-      "dev": true,
-      "requires": {
-        "acorn": "^4.0.4"
-      }
-    },
     "acorn-jsx": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
@@ -158,9 +264,9 @@
       }
     },
     "ajv-keywords": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
-      "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
+      "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
       "dev": true
     },
     "align-text": {
@@ -196,9 +302,9 @@
       }
     },
     "ansi-escapes": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
-      "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
       "dev": true
     },
     "ansi-red": {
@@ -301,6 +407,12 @@
         }
       }
     },
+    "arg": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz",
+      "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==",
+      "dev": true
+    },
     "argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -331,12 +443,6 @@
       "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
       "dev": true
     },
-    "array-equal": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
-      "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
-      "dev": true
-    },
     "array-filter": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
@@ -459,6 +565,15 @@
       "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
       "dev": true
     },
+    "async-retry": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.2.3.tgz",
+      "integrity": "sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q==",
+      "dev": true,
+      "requires": {
+        "retry": "0.12.0"
+      }
+    },
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -470,6 +585,12 @@
       "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=",
       "dev": true
     },
+    "atob-lite": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz",
+      "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=",
+      "dev": true
+    },
     "autoprefixer": {
       "version": "6.7.7",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
@@ -706,17 +827,6 @@
         }
       }
     },
-    "babel-jest": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-19.0.0.tgz",
-      "integrity": "sha1-WTI87ZmjqE01naIZyogQdP/Gzj8=",
-      "dev": true,
-      "requires": {
-        "babel-core": "^6.0.0",
-        "babel-plugin-istanbul": "^4.0.0",
-        "babel-preset-jest": "^19.0.0"
-      }
-    },
     "babel-loader": {
       "version": "6.4.1",
       "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.4.1.tgz",
@@ -757,41 +867,6 @@
         "babel-template": "^6.8.0"
       }
     },
-    "babel-plugin-istanbul": {
-      "version": "4.1.6",
-      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
-      "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==",
-      "dev": true,
-      "requires": {
-        "babel-plugin-syntax-object-rest-spread": "^6.13.0",
-        "find-up": "^2.1.0",
-        "istanbul-lib-instrument": "^1.10.1",
-        "test-exclude": "^4.2.1"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
-          "dev": true,
-          "requires": {
-            "locate-path": "^2.0.0"
-          }
-        }
-      }
-    },
-    "babel-plugin-jest-hoist": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz",
-      "integrity": "sha1-SuKgTqYSpuc2UfP95SwXiZEwS+o=",
-      "dev": true
-    },
-    "babel-plugin-syntax-object-rest-spread": {
-      "version": "6.13.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
-      "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
-      "dev": true
-    },
     "babel-plugin-transform-es2015-arrow-functions": {
       "version": "6.22.0",
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
@@ -1054,25 +1129,6 @@
         "babel-types": "^6.24.1"
       }
     },
-    "babel-polyfill": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
-      "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.26.0",
-        "core-js": "^2.5.0",
-        "regenerator-runtime": "^0.10.5"
-      },
-      "dependencies": {
-        "regenerator-runtime": {
-          "version": "0.10.5",
-          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
-          "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
-          "dev": true
-        }
-      }
-    },
     "babel-preset-es2015": {
       "version": "6.24.1",
       "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
@@ -1105,15 +1161,6 @@
         "babel-plugin-transform-regenerator": "^6.24.1"
       }
     },
-    "babel-preset-jest": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz",
-      "integrity": "sha1-ItZyAdAjJKGVgRKI6zgpS7PKw5Y=",
-      "dev": true,
-      "requires": {
-        "babel-plugin-jest-hoist": "^19.0.0"
-      }
-    },
     "babel-register": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
@@ -1208,12 +1255,6 @@
         "pascalcase": "^0.1.1"
       },
       "dependencies": {
-        "component-emitter": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
-          "dev": true
-        },
         "define-property": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
@@ -1281,6 +1322,12 @@
         "tweetnacl": "^0.14.3"
       }
     },
+    "before-after-hook": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz",
+      "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==",
+      "dev": true
+    },
     "big.js": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
@@ -1593,14 +1640,11 @@
         "electron-to-chromium": "^1.2.7"
       }
     },
-    "bser": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz",
-      "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=",
-      "dev": true,
-      "requires": {
-        "node-int64": "^0.4.0"
-      }
+    "btoa-lite": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
+      "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=",
+      "dev": true
     },
     "buble": {
       "version": "0.18.0",
@@ -1701,18 +1745,18 @@
       "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
       "dev": true
     },
+    "buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+      "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=",
+      "dev": true
+    },
     "buffer-from": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
       "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
       "dev": true
     },
-    "builtin-modules": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
-      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
-      "dev": true
-    },
     "builtin-status-codes": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
@@ -1720,9 +1764,9 @@
       "dev": true
     },
     "bytes": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.1.0.tgz",
-      "integrity": "sha1-xXSBIigSbWNp0VdpJahXnbP45aI=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
       "dev": true
     },
     "cache-base": {
@@ -1742,12 +1786,6 @@
         "unset-value": "^1.0.0"
       },
       "dependencies": {
-        "component-emitter": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
-          "dev": true
-        },
         "isobject": {
           "version": "3.0.1",
           "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
@@ -1757,9 +1795,9 @@
       }
     },
     "cached-path-relative": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
-      "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz",
+      "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==",
       "dev": true
     },
     "caller-path": {
@@ -1941,12 +1979,12 @@
       }
     },
     "cli-cursor": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
-      "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
       "dev": true,
       "requires": {
-        "restore-cursor": "^1.0.1"
+        "restore-cursor": "^2.0.0"
       }
     },
     "cli-width": {
@@ -1994,12 +2032,6 @@
         "q": "^1.1.2"
       }
     },
-    "code-point-at": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
-      "dev": true
-    },
     "collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -2108,6 +2140,12 @@
       "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
       "dev": true
     },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
     "compress-commons": {
       "version": "0.2.9",
       "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-0.2.9.tgz",
@@ -2200,30 +2238,6 @@
         "proto-list": "~1.2.1"
       }
     },
-    "connect": {
-      "version": "2.3.9",
-      "resolved": "https://registry.npmjs.org/connect/-/connect-2.3.9.tgz",
-      "integrity": "sha1-TSbdxIXDLloc8bNYVII7RyDSWlI=",
-      "dev": true,
-      "requires": {
-        "bytes": "0.1.0",
-        "cookie": "0.0.4",
-        "crc": "0.2.0",
-        "debug": "*",
-        "formidable": "1.0.11",
-        "fresh": "0.1.0",
-        "qs": "0.4.2",
-        "send": "0.0.3"
-      },
-      "dependencies": {
-        "qs": {
-          "version": "0.4.2",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-0.4.2.tgz",
-          "integrity": "sha1-PKxMhh43GoycR3CsI82o3mObjl8=",
-          "dev": true
-        }
-      }
-    },
     "console-browserify": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
@@ -2248,24 +2262,12 @@
       "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
       "dev": true
     },
-    "content-type-parser": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz",
-      "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==",
-      "dev": true
-    },
     "convert-source-map": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
       "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
       "dev": true
     },
-    "cookie": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.0.4.tgz",
-      "integrity": "sha1-VFa9R67iZm6sl26oCmEFlASD/pg=",
-      "dev": true
-    },
     "copy-descriptor": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
@@ -2321,12 +2323,6 @@
         }
       }
     },
-    "crc": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/crc/-/crc-0.2.0.tgz",
-      "integrity": "sha1-9Ehrm/ChLfg8P8oU4x4DD9q9lFQ=",
-      "dev": true
-    },
     "crc32-stream": {
       "version": "0.3.4",
       "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-0.3.4.tgz",
@@ -2450,12 +2446,6 @@
         }
       }
     },
-    "css-parse": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz",
-      "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=",
-      "dev": true
-    },
     "css-selector-tokenizer": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
@@ -2536,60 +2526,464 @@
         "source-map": "^0.5.3"
       }
     },
-    "cssom": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz",
-      "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==",
-      "dev": true
-    },
-    "cssstyle": {
-      "version": "0.2.37",
-      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
-      "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
-      "dev": true,
-      "requires": {
-        "cssom": "0.3.x"
-      }
-    },
     "ctype": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz",
       "integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=",
       "dev": true
     },
-    "d": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
-      "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
-      "dev": true,
-      "requires": {
-        "es5-ext": "^0.10.9"
-      }
-    },
     "danger": {
-      "version": "0.18.0",
-      "resolved": "https://registry.npmjs.org/danger/-/danger-0.18.0.tgz",
-      "integrity": "sha1-grwMNUa4EyvmGqvM7X+vjqubgZI=",
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/danger/-/danger-9.2.2.tgz",
+      "integrity": "sha512-tDLIFYa1KzU7HJIvn6FEurFWqn36cFPVBLvKrUqbRxJOCPONWNvpRRbHKj3HmNPEQf5bVls78V/FZz8iRs4Qlg==",
       "dev": true,
       "requires": {
-        "babel-polyfill": "^6.20.0",
-        "chalk": "^1.1.1",
-        "commander": "^2.9.0",
-        "debug": "^2.6.0",
-        "github": "^9.2.0",
-        "jest-config": "^19.0.2",
-        "jest-environment-node": "^19.0.2",
-        "jest-runtime": "^19.0.2",
-        "jsome": "^2.3.25",
+        "@babel/polyfill": "^7.2.5",
+        "@octokit/rest": "^16.14.1",
+        "async-retry": "1.2.3",
+        "chalk": "^2.3.0",
+        "commander": "^2.18.0",
+        "debug": "^4.1.1",
+        "get-stdin": "^6.0.0",
+        "gitlab": "^10.0.1",
+        "http-proxy-agent": "^2.1.0",
+        "https-proxy-agent": "^2.2.1",
+        "hyperlinker": "^1.0.0",
+        "json5": "^2.1.0",
         "jsonpointer": "^4.0.1",
+        "jsonwebtoken": "^8.4.0",
         "lodash.find": "^4.6.0",
         "lodash.includes": "^4.3.0",
-        "lodash.isobject": "^2.4.1",
+        "lodash.isobject": "^3.0.2",
         "lodash.keys": "^4.0.8",
-        "node-fetch": "^1.6.3",
-        "parse-diff": "^0.4.0",
-        "rfc6902": "^1.3.0",
-        "voca": "^1.2.0"
+        "lodash.mapvalues": "^4.6.0",
+        "lodash.memoize": "^4.1.2",
+        "memfs-or-file-map-to-github-branch": "^1.1.0",
+        "micromatch": "^3.1.10",
+        "node-cleanup": "^2.1.2",
+        "node-fetch": "^2.3.0",
+        "override-require": "^1.1.1",
+        "p-limit": "^2.1.0",
+        "parse-diff": "^0.5.1",
+        "parse-git-config": "^2.0.3",
+        "parse-github-url": "^1.0.2",
+        "parse-link-header": "^1.0.1",
+        "pinpoint": "^1.1.0",
+        "prettyjson": "^1.2.1",
+        "readline-sync": "^1.4.9",
+        "require-from-string": "^2.0.2",
+        "rfc6902": "^3.0.1",
+        "supports-hyperlinks": "^1.0.1"
+      },
+      "dependencies": {
+        "agent-base": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+          "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+          "dev": true,
+          "requires": {
+            "es6-promisify": "^5.0.0"
+          }
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "arr-diff": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+          "dev": true
+        },
+        "array-unique": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+          "dev": true
+        },
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+          "dev": true
+        },
+        "debug": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "expand-brackets": {
+          "version": "2.1.4",
+          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+          "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+          "dev": true,
+          "requires": {
+            "debug": "^2.3.3",
+            "define-property": "^0.2.5",
+            "extend-shallow": "^2.0.1",
+            "posix-character-classes": "^0.1.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "debug": {
+              "version": "2.6.9",
+              "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+              "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+              "dev": true,
+              "requires": {
+                "ms": "2.0.0"
+              }
+            },
+            "define-property": {
+              "version": "0.2.5",
+              "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+              "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+              "dev": true,
+              "requires": {
+                "is-descriptor": "^0.1.0"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            },
+            "is-accessor-descriptor": {
+              "version": "0.1.6",
+              "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+              "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+              "dev": true,
+              "requires": {
+                "kind-of": "^3.0.2"
+              },
+              "dependencies": {
+                "kind-of": {
+                  "version": "3.2.2",
+                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+                  "dev": true,
+                  "requires": {
+                    "is-buffer": "^1.1.5"
+                  }
+                }
+              }
+            },
+            "is-data-descriptor": {
+              "version": "0.1.4",
+              "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+              "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+              "dev": true,
+              "requires": {
+                "kind-of": "^3.0.2"
+              },
+              "dependencies": {
+                "kind-of": {
+                  "version": "3.2.2",
+                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+                  "dev": true,
+                  "requires": {
+                    "is-buffer": "^1.1.5"
+                  }
+                }
+              }
+            },
+            "is-descriptor": {
+              "version": "0.1.6",
+              "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+              "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+              "dev": true,
+              "requires": {
+                "is-accessor-descriptor": "^0.1.6",
+                "is-data-descriptor": "^0.1.4",
+                "kind-of": "^5.0.0"
+              }
+            },
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true
+            },
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+              "dev": true
+            }
+          }
+        },
+        "extglob": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+          "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+          "dev": true,
+          "requires": {
+            "array-unique": "^0.3.2",
+            "define-property": "^1.0.0",
+            "expand-brackets": "^2.1.4",
+            "extend-shallow": "^2.0.1",
+            "fragment-cache": "^0.2.1",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "1.0.0",
+              "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+              "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+              "dev": true,
+              "requires": {
+                "is-descriptor": "^1.0.0"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "https-proxy-agent": {
+          "version": "2.2.4",
+          "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+          "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+          "dev": true,
+          "requires": {
+            "agent-base": "^4.3.0",
+            "debug": "^3.1.0"
+          },
+          "dependencies": {
+            "debug": {
+              "version": "3.2.6",
+              "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+              "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+              "dev": true,
+              "requires": {
+                "ms": "^2.1.1"
+              }
+            }
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true
+        },
+        "json5": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
+          "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+          "dev": true
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        },
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        },
+        "node-fetch": {
+          "version": "2.6.0",
+          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
+          "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
+          "dev": true
+        },
+        "parse-diff": {
+          "version": "0.5.1",
+          "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.5.1.tgz",
+          "integrity": "sha512-/qXjo9x/pFa5bVk/ZXaJD0yr3Tf3Yp6MWWMr4vnUmumDrE0yoE6YDH2A8vmcCD/Ko3tW2o0X+zGYh2zMLXshsg==",
+          "dev": true
+        },
+        "require-from-string": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+          "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
       }
     },
     "dashdash": {
@@ -2669,6 +3063,12 @@
         }
       }
     },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "dev": true
+    },
     "deep-is": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -2753,6 +3153,12 @@
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
     },
+    "deprecation": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+      "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
+      "dev": true
+    },
     "deps-sort": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
@@ -2809,21 +3215,12 @@
       "dev": true
     },
     "doctrine": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
-      "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
       "dev": true,
       "requires": {
-        "esutils": "^2.0.2",
-        "isarray": "^1.0.0"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        }
+        "esutils": "^2.0.2"
       }
     },
     "domain-browser": {
@@ -2906,6 +3303,15 @@
         "jsbn": "~0.1.0"
       }
     },
+    "ecdsa-sig-formatter": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+      "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "ecstatic": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-1.4.1.tgz",
@@ -3017,81 +3423,19 @@
         "is-arrayish": "^0.2.1"
       }
     },
-    "es5-ext": {
-      "version": "0.10.45",
-      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz",
-      "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==",
-      "dev": true,
-      "requires": {
-        "es6-iterator": "~2.0.3",
-        "es6-symbol": "~3.1.1",
-        "next-tick": "1"
-      }
-    },
-    "es6-iterator": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
-      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.35",
-        "es6-symbol": "^3.1.1"
-      }
-    },
-    "es6-map": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
-      "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14",
-        "es6-iterator": "~2.0.1",
-        "es6-set": "~0.1.5",
-        "es6-symbol": "~3.1.1",
-        "event-emitter": "~0.3.5"
-      }
-    },
     "es6-promise": {
       "version": "4.2.4",
       "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
       "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==",
       "dev": true
     },
-    "es6-set": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
-      "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
+    "es6-promisify": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+      "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
       "dev": true,
       "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14",
-        "es6-iterator": "~2.0.1",
-        "es6-symbol": "3.1.1",
-        "event-emitter": "~0.3.5"
-      }
-    },
-    "es6-symbol": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
-      "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
-      }
-    },
-    "es6-weak-map": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
-      "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.14",
-        "es6-iterator": "^2.0.1",
-        "es6-symbol": "^3.1.1"
+        "es6-promise": "^4.0.3"
       }
     },
     "escape-string-regexp": {
@@ -3125,77 +3469,101 @@
         }
       }
     },
-    "escope": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
-      "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
-      "dev": true,
-      "requires": {
-        "es6-map": "^0.1.3",
-        "es6-weak-map": "^2.0.1",
-        "esrecurse": "^4.1.0",
-        "estraverse": "^4.1.1"
-      },
-      "dependencies": {
-        "estraverse": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
-          "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
-          "dev": true
-        }
-      }
-    },
     "eslint": {
-      "version": "2.13.1",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz",
-      "integrity": "sha1-5MyPoPAJ+4KaquI4VaKTYL4fbBE=",
+      "version": "4.18.2",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz",
+      "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==",
       "dev": true,
       "requires": {
-        "chalk": "^1.1.3",
-        "concat-stream": "^1.4.6",
-        "debug": "^2.1.1",
-        "doctrine": "^1.2.2",
-        "es6-map": "^0.1.3",
-        "escope": "^3.6.0",
-        "espree": "^3.1.6",
-        "estraverse": "^4.2.0",
+        "ajv": "^5.3.0",
+        "babel-code-frame": "^6.22.0",
+        "chalk": "^2.1.0",
+        "concat-stream": "^1.6.0",
+        "cross-spawn": "^5.1.0",
+        "debug": "^3.1.0",
+        "doctrine": "^2.1.0",
+        "eslint-scope": "^3.7.1",
+        "eslint-visitor-keys": "^1.0.0",
+        "espree": "^3.5.2",
+        "esquery": "^1.0.0",
         "esutils": "^2.0.2",
-        "file-entry-cache": "^1.1.1",
-        "glob": "^7.0.3",
-        "globals": "^9.2.0",
-        "ignore": "^3.1.2",
+        "file-entry-cache": "^2.0.0",
+        "functional-red-black-tree": "^1.0.1",
+        "glob": "^7.1.2",
+        "globals": "^11.0.1",
+        "ignore": "^3.3.3",
         "imurmurhash": "^0.1.4",
-        "inquirer": "^0.12.0",
-        "is-my-json-valid": "^2.10.0",
+        "inquirer": "^3.0.6",
         "is-resolvable": "^1.0.0",
-        "js-yaml": "^3.5.1",
-        "json-stable-stringify": "^1.0.0",
+        "js-yaml": "^3.9.1",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
         "levn": "^0.3.0",
-        "lodash": "^4.0.0",
-        "mkdirp": "^0.5.0",
-        "optionator": "^0.8.1",
-        "path-is-absolute": "^1.0.0",
-        "path-is-inside": "^1.0.1",
-        "pluralize": "^1.2.1",
-        "progress": "^1.1.8",
-        "require-uncached": "^1.0.2",
-        "shelljs": "^0.6.0",
-        "strip-json-comments": "~1.0.1",
-        "table": "^3.7.8",
-        "text-table": "~0.2.0",
-        "user-home": "^2.0.0"
+        "lodash": "^4.17.4",
+        "minimatch": "^3.0.2",
+        "mkdirp": "^0.5.1",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.8.2",
+        "path-is-inside": "^1.0.2",
+        "pluralize": "^7.0.0",
+        "progress": "^2.0.0",
+        "require-uncached": "^1.0.3",
+        "semver": "^5.3.0",
+        "strip-ansi": "^4.0.0",
+        "strip-json-comments": "~2.0.1",
+        "table": "4.0.2",
+        "text-table": "~0.2.0"
       },
       "dependencies": {
-        "estraverse": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
-          "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
           "dev": true
         },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "cross-spawn": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^4.0.1",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "debug": {
+          "version": "3.2.6",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
         "glob": {
-          "version": "7.1.2",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
-          "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+          "version": "7.1.5",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
+          "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
           "dev": true,
           "requires": {
             "fs.realpath": "^1.0.0",
@@ -3206,11 +3574,47 @@
             "path-is-absolute": "^1.0.0"
           }
         },
-        "shelljs": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz",
-          "integrity": "sha1-7GIRvtGSBEIIj+D3Cyg3Iy7SyKg=",
+        "globals": {
+          "version": "11.12.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
           "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        },
+        "progress": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+          "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
         }
       }
     },
@@ -3323,16 +3727,6 @@
       "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
       "dev": true
     },
-    "event-emitter": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
-      "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
-      }
-    },
     "event-target-shim": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-2.0.0.tgz",
@@ -3350,23 +3744,14 @@
       "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
       "dev": true
     },
-    "exec-sh": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz",
-      "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==",
-      "dev": true,
-      "requires": {
-        "merge": "^1.2.0"
-      }
-    },
     "execa": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
-      "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+      "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
       "dev": true,
       "requires": {
-        "cross-spawn": "^5.0.1",
-        "get-stream": "^3.0.0",
+        "cross-spawn": "^6.0.0",
+        "get-stream": "^4.0.0",
         "is-stream": "^1.1.0",
         "npm-run-path": "^2.0.0",
         "p-finally": "^1.0.0",
@@ -3375,24 +3760,20 @@
       },
       "dependencies": {
         "cross-spawn": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "version": "6.0.5",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
           "dev": true,
           "requires": {
-            "lru-cache": "^4.0.1",
+            "nice-try": "^1.0.4",
+            "path-key": "^2.0.1",
+            "semver": "^5.5.0",
             "shebang-command": "^1.2.0",
             "which": "^1.2.9"
           }
         }
       }
     },
-    "exit-hook": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
-      "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
-      "dev": true
-    },
     "expand-brackets": {
       "version": "0.1.5",
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
@@ -3411,6 +3792,15 @@
         "fill-range": "^2.1.0"
       }
     },
+    "expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
     "extend": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -3434,6 +3824,21 @@
           "requires": {
             "is-plain-object": "^2.0.4"
           }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true
         }
       }
     },
@@ -3490,21 +3895,21 @@
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
       "dev": true
     },
+    "fast-url-parser": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
+      "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=",
+      "dev": true,
+      "requires": {
+        "punycode": "^1.3.2"
+      }
+    },
     "fastparse": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
       "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=",
       "dev": true
     },
-    "fb-watchman": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz",
-      "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=",
-      "dev": true,
-      "requires": {
-        "bser": "^2.0.0"
-      }
-    },
     "fd-slicer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
@@ -3515,19 +3920,18 @@
       }
     },
     "figures": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
-      "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
       "dev": true,
       "requires": {
-        "escape-string-regexp": "^1.0.5",
-        "object-assign": "^4.1.0"
+        "escape-string-regexp": "^1.0.5"
       }
     },
     "file-entry-cache": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz",
-      "integrity": "sha1-RMYepgeuS+nBQC9B9EJwy/4zT/g=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
       "dev": true,
       "requires": {
         "flat-cache": "^1.2.1",
@@ -3719,12 +4123,6 @@
         "samsam": "1.x"
       }
     },
-    "formidable": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.11.tgz",
-      "integrity": "sha1-aPYzJaA15kS297s9ESQ7l2HeGzA=",
-      "dev": true
-    },
     "fragment-cache": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -3734,10 +4132,10 @@
         "map-cache": "^0.2.2"
       }
     },
-    "fresh": {
+    "fs-exists-sync": {
       "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz",
-      "integrity": "sha1-A+SwF4Qk5MLV0ZpU2IFM3JeTSFA=",
+      "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
+      "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=",
       "dev": true
     },
     "fs-extra": {
@@ -3778,7 +4176,8 @@
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
           "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -3802,13 +4201,15 @@
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
           "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
           "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
           "dev": true,
+          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -3825,19 +4226,22 @@
           "version": "1.1.0",
           "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
           "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
           "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
           "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -3968,7 +4372,8 @@
           "version": "2.0.3",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
           "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "ini": {
           "version": "1.3.5",
@@ -3982,6 +4387,7 @@
           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
           "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
           "dev": true,
+          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -3998,6 +4404,7 @@
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
           "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
           "dev": true,
+          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -4006,13 +4413,15 @@
           "version": "0.0.8",
           "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
           "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "minipass": {
           "version": "2.2.4",
           "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz",
           "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
           "dev": true,
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.1",
             "yallist": "^3.0.0"
@@ -4033,6 +4442,7 @@
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
           "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
           "dev": true,
+          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -4121,7 +4531,8 @@
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
           "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -4135,6 +4546,7 @@
           "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
           "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
           "dev": true,
+          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -4230,7 +4642,8 @@
           "version": "5.1.1",
           "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
           "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -4272,6 +4685,7 @@
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
           "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
           "dev": true,
+          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -4293,6 +4707,7 @@
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
           "dev": true,
+          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -4341,13 +4756,15 @@
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
           "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "yallist": {
           "version": "3.0.2",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
           "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
-          "dev": true
+          "dev": true,
+          "optional": true
         }
       }
     },
@@ -4384,24 +4801,27 @@
       "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==",
       "dev": true
     },
-    "get-caller-file": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
-      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
-      "dev": true
-    },
     "get-func-name": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
       "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
       "dev": true
     },
-    "get-stream": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-      "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+    "get-stdin": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
+      "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
       "dev": true
     },
+    "get-stream": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+      "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+      "dev": true,
+      "requires": {
+        "pump": "^3.0.0"
+      }
+    },
     "get-value": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -4416,6 +4836,28 @@
         "assert-plus": "^1.0.0"
       }
     },
+    "git-config-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz",
+      "integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "fs-exists-sync": "^0.1.0",
+        "homedir-polyfill": "^1.0.0"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
     "github": {
       "version": "9.3.1",
       "resolved": "https://registry.npmjs.org/github/-/github-9.3.1.tgz",
@@ -4428,6 +4870,51 @@
         "netrc": "^0.1.4"
       }
     },
+    "gitlab": {
+      "version": "10.2.1",
+      "resolved": "https://registry.npmjs.org/gitlab/-/gitlab-10.2.1.tgz",
+      "integrity": "sha512-z+DxRF1C9uayVbocs9aJkJz+kGy14TSm1noB/rAIEBbXOkOYbjKxyuqJzt+0zeFpXFdgA0yq6DVVbvM7HIfGwg==",
+      "dev": true,
+      "requires": {
+        "form-data": "^2.5.0",
+        "humps": "^2.0.1",
+        "ky": "^0.12.0",
+        "ky-universal": "^0.3.0",
+        "li": "^1.3.0",
+        "query-string": "^6.8.2",
+        "universal-url": "^2.0.0"
+      },
+      "dependencies": {
+        "form-data": {
+          "version": "2.5.1",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+          "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+          "dev": true,
+          "requires": {
+            "asynckit": "^0.4.0",
+            "combined-stream": "^1.0.6",
+            "mime-types": "^2.1.12"
+          }
+        },
+        "query-string": {
+          "version": "6.8.3",
+          "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.3.tgz",
+          "integrity": "sha512-llcxWccnyaWlODe7A9hRjkvdCKamEKTh+wH8ITdTc3OhchaqUZteiSCX/2ablWHVrkVIe04dntnaZJ7BdyW0lQ==",
+          "dev": true,
+          "requires": {
+            "decode-uri-component": "^0.2.0",
+            "split-on-first": "^1.0.0",
+            "strict-uri-encode": "^2.0.0"
+          }
+        },
+        "strict-uri-encode": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+          "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
+          "dev": true
+        }
+      }
+    },
     "glob": {
       "version": "5.0.15",
       "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
@@ -4460,6 +4947,34 @@
         "is-glob": "^2.0.0"
       }
     },
+    "glob-slash": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/glob-slash/-/glob-slash-1.0.0.tgz",
+      "integrity": "sha1-/lLvpDMjP3Si/mTHq7m8hIICq5U=",
+      "dev": true
+    },
+    "glob-slasher": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/glob-slasher/-/glob-slasher-1.0.1.tgz",
+      "integrity": "sha1-dHoOW7IiZC7hDT4FRD4QlJPLD44=",
+      "dev": true,
+      "requires": {
+        "glob-slash": "^1.0.0",
+        "lodash.isobject": "^2.4.1",
+        "toxic": "^1.0.0"
+      },
+      "dependencies": {
+        "lodash.isobject": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz",
+          "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=",
+          "dev": true,
+          "requires": {
+            "lodash._objecttypes": "~2.4.1"
+          }
+        }
+      }
+    },
     "globals": {
       "version": "9.18.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
@@ -4520,24 +5035,54 @@
       "dev": true
     },
     "handlebars": {
-      "version": "4.0.11",
-      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
-      "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
+      "version": "4.0.14",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.14.tgz",
+      "integrity": "sha512-E7tDoyAA8ilZIV3xDJgl18sX3M8xB9/fMw8+mfW4msLW8jlX97bAnWgT3pmaNXuvzIEgSBMnAHfuXsB2hdzfow==",
       "dev": true,
       "requires": {
-        "async": "^1.4.0",
+        "async": "^2.5.0",
         "optimist": "^0.6.1",
-        "source-map": "^0.4.4",
-        "uglify-js": "^2.6"
+        "source-map": "^0.6.1",
+        "uglify-js": "^3.1.4"
       },
       "dependencies": {
-        "source-map": {
-          "version": "0.4.4",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
-          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+        "async": {
+          "version": "2.6.3",
+          "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+          "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
           "dev": true,
           "requires": {
-            "amdefine": ">=0.0.4"
+            "lodash": "^4.17.14"
+          }
+        },
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+          "dev": true,
+          "optional": true
+        },
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "uglify-js": {
+          "version": "3.6.5",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.5.tgz",
+          "integrity": "sha512-7L3W+Npia1OCr5Blp4/Vw83tK1mu5gnoIURtT1fUVfQ3Kf8WStWV6NJz0fdoBJZls0KlweruRTLVe6XLafmy5g==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "commander": "~2.20.3",
+            "source-map": "~0.6.1"
           }
         }
       }
@@ -4656,6 +5201,12 @@
         "pinkie-promise": "^2.0.0"
       }
     },
+    "hasurl": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hasurl/-/hasurl-1.0.0.tgz",
+      "integrity": "sha512-43ypUd3DbwyCT01UYpA99AEZxZ4aKtRxWGBHEIbjcOsUghd9YUON0C+JF6isNjaiwC/UF5neaUudy6JS9jZPZQ==",
+      "dev": true
+    },
     "hawk": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz",
@@ -4690,11 +5241,14 @@
         "os-tmpdir": "^1.0.1"
       }
     },
-    "hosted-git-info": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
-      "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
-      "dev": true
+    "homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
     },
     "html-comment-regex": {
       "version": "1.1.1",
@@ -4702,15 +5256,6 @@
       "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=",
       "dev": true
     },
-    "html-encoding-sniffer": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
-      "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
-      "dev": true,
-      "requires": {
-        "whatwg-encoding": "^1.0.1"
-      }
-    },
     "htmlescape": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
@@ -4748,6 +5293,36 @@
         }
       }
     },
+    "http-proxy-agent": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
+      "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+      "dev": true,
+      "requires": {
+        "agent-base": "4",
+        "debug": "3.1.0"
+      },
+      "dependencies": {
+        "agent-base": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+          "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+          "dev": true,
+          "requires": {
+            "es6-promisify": "^5.0.0"
+          }
+        },
+        "debug": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        }
+      }
+    },
     "http-server": {
       "version": "0.9.0",
       "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.9.0.tgz",
@@ -4799,6 +5374,18 @@
         "extend": "3"
       }
     },
+    "humps": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz",
+      "integrity": "sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao=",
+      "dev": true
+    },
+    "hyperlinker": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz",
+      "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==",
+      "dev": true
+    },
     "iconv-lite": {
       "version": "0.4.23",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
@@ -4825,13 +5412,6 @@
       "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
       "dev": true
     },
-    "image-size": {
-      "version": "0.5.5",
-      "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
-      "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
-      "dev": true,
-      "optional": true
-    },
     "imurmurhash": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -4881,24 +5461,83 @@
       }
     },
     "inquirer": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
-      "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
+      "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
       "dev": true,
       "requires": {
-        "ansi-escapes": "^1.1.0",
-        "ansi-regex": "^2.0.0",
-        "chalk": "^1.0.0",
-        "cli-cursor": "^1.0.1",
+        "ansi-escapes": "^3.0.0",
+        "chalk": "^2.0.0",
+        "cli-cursor": "^2.1.0",
         "cli-width": "^2.0.0",
-        "figures": "^1.3.5",
+        "external-editor": "^2.0.4",
+        "figures": "^2.0.0",
         "lodash": "^4.3.0",
-        "readline2": "^1.0.1",
-        "run-async": "^0.1.0",
-        "rx-lite": "^3.1.2",
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.0",
+        "mute-stream": "0.0.7",
+        "run-async": "^2.2.0",
+        "rx-lite": "^4.0.8",
+        "rx-lite-aggregates": "^4.0.8",
+        "string-width": "^2.1.0",
+        "strip-ansi": "^4.0.0",
         "through": "^2.3.6"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "rx-lite": {
+          "version": "4.0.8",
+          "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+          "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
       }
     },
     "insert-module-globals": {
@@ -4934,12 +5573,6 @@
         "loose-envify": "^1.0.0"
       }
     },
-    "invert-kv": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
-      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
-      "dev": true
-    },
     "ipv4": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/ipv4/-/ipv4-1.0.4.tgz",
@@ -4957,12 +5590,6 @@
       "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=",
       "dev": true
     },
-    "is": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz",
-      "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU=",
-      "dev": true
-    },
     "is-absolute-url": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
@@ -4999,15 +5626,6 @@
       "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
       "dev": true
     },
-    "is-builtin-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
-      "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
-      "dev": true,
-      "requires": {
-        "builtin-modules": "^1.0.0"
-      }
-    },
     "is-data-descriptor": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
@@ -5079,13 +5697,10 @@
       }
     },
     "is-fullwidth-code-point": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
-      "dev": true,
-      "requires": {
-        "number-is-nan": "^1.0.0"
-      }
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true
     },
     "is-glob": {
       "version": "2.0.1",
@@ -5161,18 +5776,18 @@
       "dev": true
     },
     "is-plain-object": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
-      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
+      "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
       "dev": true,
       "requires": {
-        "isobject": "^3.0.1"
+        "isobject": "^4.0.0"
       },
       "dependencies": {
         "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
+          "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==",
           "dev": true
         }
       }
@@ -5227,12 +5842,6 @@
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
       "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
     },
-    "is-utf8": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
-      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
-      "dev": true
-    },
     "is-windows": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -5288,27 +5897,6 @@
       "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
       "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
     },
-    "istanbul-lib-coverage": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz",
-      "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==",
-      "dev": true
-    },
-    "istanbul-lib-instrument": {
-      "version": "1.10.1",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz",
-      "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==",
-      "dev": true,
-      "requires": {
-        "babel-generator": "^6.18.0",
-        "babel-template": "^6.16.0",
-        "babel-traverse": "^6.18.0",
-        "babel-types": "^6.18.0",
-        "babylon": "^6.18.0",
-        "istanbul-lib-coverage": "^1.2.0",
-        "semver": "^5.3.0"
-      }
-    },
     "jade": {
       "version": "0.26.3",
       "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz",
@@ -5333,259 +5921,6 @@
         }
       }
     },
-    "jest-config": {
-      "version": "19.0.4",
-      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-19.0.4.tgz",
-      "integrity": "sha1-QpgCEdRkF+kcp6v/0IbCcCNPc/0=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.1",
-        "jest-environment-jsdom": "^19.0.2",
-        "jest-environment-node": "^19.0.2",
-        "jest-jasmine2": "^19.0.2",
-        "jest-regex-util": "^19.0.0",
-        "jest-resolve": "^19.0.2",
-        "jest-validate": "^19.0.2",
-        "pretty-format": "^19.0.0"
-      }
-    },
-    "jest-diff": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-19.0.0.tgz",
-      "integrity": "sha1-0VY8/FbItgIymI+8BdTRbtkPBjw=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.3",
-        "diff": "^3.0.0",
-        "jest-matcher-utils": "^19.0.0",
-        "pretty-format": "^19.0.0"
-      }
-    },
-    "jest-environment-jsdom": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz",
-      "integrity": "sha1-ztqFnEpLlKs15N59q1S5JvKT5KM=",
-      "dev": true,
-      "requires": {
-        "jest-mock": "^19.0.0",
-        "jest-util": "^19.0.2",
-        "jsdom": "^9.11.0"
-      }
-    },
-    "jest-environment-node": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-19.0.2.tgz",
-      "integrity": "sha1-boQHnbh+0h0MBeH5Zp8gexFv6Zs=",
-      "dev": true,
-      "requires": {
-        "jest-mock": "^19.0.0",
-        "jest-util": "^19.0.2"
-      }
-    },
-    "jest-file-exists": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/jest-file-exists/-/jest-file-exists-19.0.0.tgz",
-      "integrity": "sha1-zKLlh6EeyS4kz+qz+KlNZX8/zrg=",
-      "dev": true
-    },
-    "jest-haste-map": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-19.0.2.tgz",
-      "integrity": "sha1-KGSEw6Fuhtp4crCHfDXc4ww9bwc=",
-      "dev": true,
-      "requires": {
-        "fb-watchman": "^2.0.0",
-        "graceful-fs": "^4.1.6",
-        "micromatch": "^2.3.11",
-        "sane": "~1.5.0",
-        "worker-farm": "^1.3.1"
-      }
-    },
-    "jest-jasmine2": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz",
-      "integrity": "sha1-FnmRrIJZgfsagArxJug6/MqDLHM=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.6",
-        "jest-matcher-utils": "^19.0.0",
-        "jest-matchers": "^19.0.0",
-        "jest-message-util": "^19.0.0",
-        "jest-snapshot": "^19.0.2"
-      }
-    },
-    "jest-matcher-utils": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz",
-      "integrity": "sha1-Xs2bY1ZdKwAfYfv37Ex/U3lkVk0=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.3",
-        "pretty-format": "^19.0.0"
-      }
-    },
-    "jest-matchers": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-19.0.0.tgz",
-      "integrity": "sha1-x07Mbr/sBvOEdnuk1vpKQtZ1V1Q=",
-      "dev": true,
-      "requires": {
-        "jest-diff": "^19.0.0",
-        "jest-matcher-utils": "^19.0.0",
-        "jest-message-util": "^19.0.0",
-        "jest-regex-util": "^19.0.0"
-      }
-    },
-    "jest-message-util": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-19.0.0.tgz",
-      "integrity": "sha1-cheWuJwOTXYWBvm6jLgoo7YkZBY=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.1",
-        "micromatch": "^2.3.11"
-      }
-    },
-    "jest-mock": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-19.0.0.tgz",
-      "integrity": "sha1-ZwOGQelgerLOCOxKjLg6q7yJnQE=",
-      "dev": true
-    },
-    "jest-regex-util": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-19.0.0.tgz",
-      "integrity": "sha1-t3VFhxEq7eFFZRC7H2r+dO9ZhpE=",
-      "dev": true
-    },
-    "jest-resolve": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-19.0.2.tgz",
-      "integrity": "sha1-V5NXXeTweuwy99f/DGwYGWPu+zw=",
-      "dev": true,
-      "requires": {
-        "browser-resolve": "^1.11.2",
-        "jest-haste-map": "^19.0.0",
-        "resolve": "^1.2.0"
-      },
-      "dependencies": {
-        "resolve": {
-          "version": "1.8.1",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
-          "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
-          "dev": true,
-          "requires": {
-            "path-parse": "^1.0.5"
-          }
-        }
-      }
-    },
-    "jest-runtime": {
-      "version": "19.0.4",
-      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-19.0.4.tgz",
-      "integrity": "sha1-8WfZ8TR3UvICc2EGeSZIU0n8wkU=",
-      "dev": true,
-      "requires": {
-        "babel-core": "^6.0.0",
-        "babel-jest": "^19.0.0",
-        "babel-plugin-istanbul": "^4.0.0",
-        "chalk": "^1.1.3",
-        "graceful-fs": "^4.1.6",
-        "jest-config": "^19.0.2",
-        "jest-file-exists": "^19.0.0",
-        "jest-haste-map": "^19.0.0",
-        "jest-regex-util": "^19.0.0",
-        "jest-resolve": "^19.0.2",
-        "jest-util": "^19.0.2",
-        "json-stable-stringify": "^1.0.1",
-        "micromatch": "^2.3.11",
-        "strip-bom": "3.0.0",
-        "yargs": "^6.3.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true
-        },
-        "cliui": {
-          "version": "3.2.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
-          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
-          "dev": true,
-          "requires": {
-            "string-width": "^1.0.1",
-            "strip-ansi": "^3.0.1",
-            "wrap-ansi": "^2.0.0"
-          }
-        },
-        "yargs": {
-          "version": "6.6.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
-          "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^3.0.0",
-            "cliui": "^3.2.0",
-            "decamelize": "^1.1.1",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^1.4.0",
-            "read-pkg-up": "^1.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^1.0.2",
-            "which-module": "^1.0.0",
-            "y18n": "^3.2.1",
-            "yargs-parser": "^4.2.0"
-          }
-        }
-      }
-    },
-    "jest-snapshot": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-19.0.2.tgz",
-      "integrity": "sha1-nBshYhT3GHw4v9XHCx76sWsP9Qs=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.3",
-        "jest-diff": "^19.0.0",
-        "jest-file-exists": "^19.0.0",
-        "jest-matcher-utils": "^19.0.0",
-        "jest-util": "^19.0.2",
-        "natural-compare": "^1.4.0",
-        "pretty-format": "^19.0.0"
-      }
-    },
-    "jest-util": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-19.0.2.tgz",
-      "integrity": "sha1-4KAjKiq55rK1Nmi9s1NMK1l37UE=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.1",
-        "graceful-fs": "^4.1.6",
-        "jest-file-exists": "^19.0.0",
-        "jest-message-util": "^19.0.0",
-        "jest-mock": "^19.0.0",
-        "jest-validate": "^19.0.2",
-        "leven": "^2.0.0",
-        "mkdirp": "^0.5.1"
-      }
-    },
-    "jest-validate": {
-      "version": "19.0.2",
-      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-19.0.2.tgz",
-      "integrity": "sha1-3FNN9fEnjVtj3zKxQkHU2/ckTAw=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.1",
-        "jest-matcher-utils": "^19.0.0",
-        "leven": "^2.0.0",
-        "pretty-format": "^19.0.0"
-      }
-    },
     "js-base64": {
       "version": "2.4.8",
       "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz",
@@ -5634,190 +5969,12 @@
       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
       "optional": true
     },
-    "jsdom": {
-      "version": "9.12.0",
-      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz",
-      "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=",
-      "dev": true,
-      "requires": {
-        "abab": "^1.0.3",
-        "acorn": "^4.0.4",
-        "acorn-globals": "^3.1.0",
-        "array-equal": "^1.0.0",
-        "content-type-parser": "^1.0.1",
-        "cssom": ">= 0.3.2 < 0.4.0",
-        "cssstyle": ">= 0.2.37 < 0.3.0",
-        "escodegen": "^1.6.1",
-        "html-encoding-sniffer": "^1.0.1",
-        "nwmatcher": ">= 1.3.9 < 2.0.0",
-        "parse5": "^1.5.1",
-        "request": "^2.79.0",
-        "sax": "^1.2.1",
-        "symbol-tree": "^3.2.1",
-        "tough-cookie": "^2.3.2",
-        "webidl-conversions": "^4.0.0",
-        "whatwg-encoding": "^1.0.1",
-        "whatwg-url": "^4.3.0",
-        "xml-name-validator": "^2.0.1"
-      }
-    },
     "jsesc": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
       "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
       "dev": true
     },
-    "jsome": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/jsome/-/jsome-2.5.0.tgz",
-      "integrity": "sha1-XkF+70NB/+uD7ov6kmWzbVb+Se0=",
-      "dev": true,
-      "requires": {
-        "chalk": "^2.3.0",
-        "json-stringify-safe": "^5.0.1",
-        "yargs": "^11.0.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "camelcase": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
-          "dev": true
-        },
-        "chalk": {
-          "version": "2.4.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
-          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "cliui": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
-          "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
-          "dev": true,
-          "requires": {
-            "string-width": "^2.1.1",
-            "strip-ansi": "^4.0.0",
-            "wrap-ansi": "^2.0.0"
-          }
-        },
-        "find-up": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
-          "dev": true,
-          "requires": {
-            "locate-path": "^2.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "os-locale": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
-          "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
-          "dev": true,
-          "requires": {
-            "execa": "^0.7.0",
-            "lcid": "^1.0.0",
-            "mem": "^1.1.0"
-          }
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-          "dev": true,
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^3.0.0"
-          }
-        },
-        "supports-color": {
-          "version": "5.4.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
-          "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        },
-        "which-module": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-          "dev": true
-        },
-        "yargs": {
-          "version": "11.1.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
-          "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
-          "dev": true,
-          "requires": {
-            "cliui": "^4.0.0",
-            "decamelize": "^1.1.1",
-            "find-up": "^2.1.0",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^2.0.0",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^2.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^3.2.1",
-            "yargs-parser": "^9.0.2"
-          }
-        },
-        "yargs-parser": {
-          "version": "9.0.2",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
-          "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^4.1.0"
-          }
-        }
-      }
-    },
     "json-loader": {
       "version": "0.5.7",
       "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz",
@@ -5834,15 +5991,6 @@
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
       "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
     },
-    "json-stable-stringify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
-      "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
-      "dev": true,
-      "requires": {
-        "jsonify": "~0.0.0"
-      }
-    },
     "json-stable-stringify-without-jsonify": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
@@ -5896,6 +6044,38 @@
       "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
       "dev": true
     },
+    "jsonwebtoken": {
+      "version": "8.5.1",
+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+      "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+      "dev": true,
+      "requires": {
+        "jws": "^3.2.2",
+        "lodash.includes": "^4.3.0",
+        "lodash.isboolean": "^3.0.3",
+        "lodash.isinteger": "^4.0.4",
+        "lodash.isnumber": "^3.0.3",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.isstring": "^4.0.1",
+        "lodash.once": "^4.0.0",
+        "ms": "^2.1.1",
+        "semver": "^5.6.0"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
+      }
+    },
     "jsprim": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -5907,6 +6087,27 @@
         "verror": "1.10.0"
       }
     },
+    "jwa": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+      "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+      "dev": true,
+      "requires": {
+        "buffer-equal-constant-time": "1.0.1",
+        "ecdsa-sig-formatter": "1.0.11",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "jws": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+      "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+      "dev": true,
+      "requires": {
+        "jwa": "^1.4.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "kew": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz",
@@ -5931,6 +6132,30 @@
         "graceful-fs": "^4.1.9"
       }
     },
+    "ky": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/ky/-/ky-0.12.0.tgz",
+      "integrity": "sha512-t9b7v3V2fGwAcQnnDDQwKQGF55eWrf4pwi1RN08Fy8b/9GEwV7Ea0xQiaSW6ZbeghBHIwl8kgnla4vVo9seepQ==",
+      "dev": true
+    },
+    "ky-universal": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/ky-universal/-/ky-universal-0.3.0.tgz",
+      "integrity": "sha512-CM4Bgb2zZZpsprcjI6DNYTaH3oGHXL2u7BU4DK+lfCuC4snkt9/WRpMYeKbBbXscvKkeqBwzzjFX2WwmKY5K/A==",
+      "dev": true,
+      "requires": {
+        "abort-controller": "^3.0.0",
+        "node-fetch": "^2.6.0"
+      },
+      "dependencies": {
+        "node-fetch": {
+          "version": "2.6.0",
+          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
+          "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
+          "dev": true
+        }
+      }
+    },
     "labeled-stream-splicer": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz",
@@ -5979,74 +6204,6 @@
         }
       }
     },
-    "lcid": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
-      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
-      "dev": true,
-      "requires": {
-        "invert-kv": "^1.0.0"
-      }
-    },
-    "less": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/less/-/less-3.0.4.tgz",
-      "integrity": "sha512-q3SyEnPKbk9zh4l36PGeW2fgynKu+FpbhiUNx/yaiBUQ3V0CbACCgb9FzYWcRgI2DJlP6eI4jc8XPrCTi55YcQ==",
-      "dev": true,
-      "requires": {
-        "errno": "^0.1.1",
-        "graceful-fs": "^4.1.2",
-        "image-size": "~0.5.0",
-        "mime": "^1.4.1",
-        "mkdirp": "^0.5.0",
-        "promise": "^7.1.1",
-        "request": "^2.83.0",
-        "source-map": "~0.6.0"
-      },
-      "dependencies": {
-        "asap": {
-          "version": "2.0.6",
-          "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-          "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
-          "dev": true,
-          "optional": true
-        },
-        "promise": {
-          "version": "7.3.1",
-          "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
-          "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "asap": "~2.0.3"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "less-middleware": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/less-middleware/-/less-middleware-3.0.1.tgz",
-      "integrity": "sha512-FCG4zGd7c/lKMWGDzzkfU9Lcndfjc4TcSnuRwUtJ4E+NxPMuDGe7lJA1rOn+SI9x2lak+s4b6sQkcPa45eqKiw==",
-      "dev": true,
-      "requires": {
-        "less": "~3.0.4",
-        "mkdirp": "~0.5.1",
-        "node.extend": "~2.0.0"
-      }
-    },
-    "leven": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
-      "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=",
-      "dev": true
-    },
     "levn": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@@ -6057,35 +6214,11 @@
         "type-check": "~0.3.2"
       }
     },
-    "load-json-file": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
-      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "parse-json": "^2.2.0",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0",
-        "strip-bom": "^2.0.0"
-      },
-      "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        },
-        "strip-bom": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-          "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
-          "dev": true,
-          "requires": {
-            "is-utf8": "^0.2.0"
-          }
-        }
-      }
+    "li": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/li/-/li-1.3.0.tgz",
+      "integrity": "sha1-IsWbyu+qmo7zWc91l4TkvxBq6hs=",
+      "dev": true
     },
     "loader-utils": {
       "version": "0.2.17",
@@ -6099,24 +6232,6 @@
         "object-assign": "^4.0.1"
       }
     },
-    "locate-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-      "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
-      "dev": true,
-      "requires": {
-        "p-locate": "^2.0.0",
-        "path-exists": "^3.0.0"
-      },
-      "dependencies": {
-        "path-exists": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
-        }
-      }
-    },
     "lodash": {
       "version": "4.17.10",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
@@ -6141,20 +6256,53 @@
       "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=",
       "dev": true
     },
+    "lodash.get": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+      "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
+      "dev": true
+    },
     "lodash.includes": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
       "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=",
       "dev": true
     },
+    "lodash.isboolean": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+      "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=",
+      "dev": true
+    },
+    "lodash.isinteger": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+      "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=",
+      "dev": true
+    },
+    "lodash.isnumber": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+      "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=",
+      "dev": true
+    },
     "lodash.isobject": {
-      "version": "2.4.1",
-      "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz",
-      "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=",
-      "dev": true,
-      "requires": {
-        "lodash._objecttypes": "~2.4.1"
-      }
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
+      "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=",
+      "dev": true
+    },
+    "lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
+      "dev": true
+    },
+    "lodash.isstring": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+      "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
+      "dev": true
     },
     "lodash.keys": {
       "version": "4.2.0",
@@ -6162,12 +6310,36 @@
       "integrity": "sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU=",
       "dev": true
     },
+    "lodash.mapvalues": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz",
+      "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=",
+      "dev": true
+    },
     "lodash.memoize": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
       "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
       "dev": true
     },
+    "lodash.once": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+      "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=",
+      "dev": true
+    },
+    "lodash.set": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
+      "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
+      "dev": true
+    },
+    "lodash.sortby": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+      "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
+      "dev": true
+    },
     "lodash.uniq": {
       "version": "4.5.0",
       "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@@ -6618,6 +6790,12 @@
         }
       }
     },
+    "macos-release": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz",
+      "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==",
+      "dev": true
+    },
     "magic-string": {
       "version": "0.16.0",
       "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.16.0.tgz",
@@ -6627,15 +6805,6 @@
         "vlq": "^0.2.1"
       }
     },
-    "makeerror": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
-      "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=",
-      "dev": true,
-      "requires": {
-        "tmpl": "1.0.x"
-      }
-    },
     "map-cache": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -6674,14 +6843,11 @@
         "is-buffer": "~1.1.1"
       }
     },
-    "mem": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
-      "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
-      "dev": true,
-      "requires": {
-        "mimic-fn": "^1.0.0"
-      }
+    "memfs-or-file-map-to-github-branch": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.1.2.tgz",
+      "integrity": "sha512-D2JKK2DTuVYQqquBWco3K6UfSVyVwmd58dgNqh+TgxHOZdTmR8I130gjMbVCkemDl/EzqDA62417cJxKL3/FFA==",
+      "dev": true
     },
     "memory-fs": {
       "version": "0.3.0",
@@ -6725,12 +6891,6 @@
         }
       }
     },
-    "merge": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz",
-      "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=",
-      "dev": true
-    },
     "micromatch": {
       "version": "2.3.11",
       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
@@ -6798,9 +6958,9 @@
       "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
     },
     "mixin-deep": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
-      "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
       "dev": true,
       "requires": {
         "for-in": "^1.0.2",
@@ -6815,6 +6975,21 @@
           "requires": {
             "is-plain-object": "^2.0.4"
           }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true
         }
       }
     },
@@ -7022,9 +7197,9 @@
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
     },
     "mute-stream": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
-      "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
       "dev": true
     },
     "nan": {
@@ -7091,10 +7266,16 @@
       "integrity": "sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ=",
       "dev": true
     },
-    "next-tick": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
-      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
+    "node-cleanup": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz",
+      "integrity": "sha1-esGavSl+Caf3KnFUXZUbUX5N3iw=",
       "dev": true
     },
     "node-fetch": {
@@ -7107,12 +7288,6 @@
         "is-stream": "^1.0.1"
       }
     },
-    "node-int64": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
-      "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=",
-      "dev": true
-    },
     "node-libs-browser": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.7.0.tgz",
@@ -7178,15 +7353,6 @@
         }
       }
     },
-    "node.extend": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.0.tgz",
-      "integrity": "sha1-dSWih1Z36lNHhKXhCseJVhOWFN8=",
-      "dev": true,
-      "requires": {
-        "is": "^3.2.1"
-      }
-    },
     "nopt": {
       "version": "3.0.6",
       "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
@@ -7196,18 +7362,6 @@
         "abbrev": "1"
       }
     },
-    "normalize-package-data": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
-      "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
-      "dev": true,
-      "requires": {
-        "hosted-git-info": "^2.1.4",
-        "is-builtin-module": "^1.0.0",
-        "semver": "2 || 3 || 4 || 5",
-        "validate-npm-package-license": "^3.0.1"
-      }
-    },
     "normalize-path": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
@@ -7256,12 +7410,6 @@
       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
       "dev": true
     },
-    "nwmatcher": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz",
-      "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==",
-      "dev": true
-    },
     "oauth-sign": {
       "version": "0.8.2",
       "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
@@ -7339,6 +7487,12 @@
         }
       }
     },
+    "octokit-pagination-methods": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz",
+      "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==",
+      "dev": true
+    },
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -7349,10 +7503,13 @@
       }
     },
     "onetime": {
-      "version": "1.1.0",
-      "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
-      "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
-      "dev": true
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "^1.0.0"
+      }
     },
     "opener": {
       "version": "1.4.3",
@@ -7413,13 +7570,14 @@
       "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
       "dev": true
     },
-    "os-locale": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
-      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+    "os-name": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz",
+      "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==",
       "dev": true,
       "requires": {
-        "lcid": "^1.0.0"
+        "macos-release": "^2.2.0",
+        "windows-release": "^3.1.0"
       }
     },
     "os-tmpdir": {
@@ -7428,6 +7586,12 @@
       "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
       "dev": true
     },
+    "override-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/override-require/-/override-require-1.1.1.tgz",
+      "integrity": "sha1-auIvresfhQ/7DPTCD/e4fl62UN8=",
+      "dev": true
+    },
     "p-finally": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
@@ -7435,21 +7599,12 @@
       "dev": true
     },
     "p-limit": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
-      "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
+      "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
       "dev": true,
       "requires": {
-        "p-try": "^1.0.0"
-      }
-    },
-    "p-locate": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
-      "dev": true,
-      "requires": {
-        "p-limit": "^1.1.0"
+        "p-try": "^2.0.0"
       }
     },
     "p-map": {
@@ -7459,9 +7614,9 @@
       "dev": true
     },
     "p-try": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
       "dev": true
     },
     "pako": {
@@ -7484,6 +7639,23 @@
       "integrity": "sha512-YYQzII66NqysdPgDVxzbdwNXMv5Ww562JSZSXZ4RIPoolzD7yqA4crgD8swrs+JNcvjoZMKMiT4kGcLYvf6IoA==",
       "dev": true
     },
+    "parse-git-config": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-2.0.3.tgz",
+      "integrity": "sha512-Js7ueMZOVSZ3tP8C7E3KZiHv6QQl7lnJ+OkbxoaFazzSa2KyEHqApfGbU3XboUgUnq4ZuUmskUpYKTNx01fm5A==",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "git-config-path": "^1.0.1",
+        "ini": "^1.3.5"
+      }
+    },
+    "parse-github-url": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz",
+      "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==",
+      "dev": true
+    },
     "parse-glob": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
@@ -7505,16 +7677,25 @@
         "error-ex": "^1.2.0"
       }
     },
+    "parse-link-header": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz",
+      "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=",
+      "dev": true,
+      "requires": {
+        "xtend": "~4.0.1"
+      }
+    },
     "parse-ms": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz",
       "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=",
       "dev": true
     },
-    "parse5": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
-      "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=",
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
       "dev": true
     },
     "pascalcase": {
@@ -7577,25 +7758,6 @@
         "isarray": "0.0.1"
       }
     },
-    "path-type": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
-      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
-      },
-      "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        }
-      }
-    },
     "pathval": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
@@ -7670,6 +7832,12 @@
         "pinkie": "^2.0.0"
       }
     },
+    "pinpoint": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/pinpoint/-/pinpoint-1.1.0.tgz",
+      "integrity": "sha1-DPd1eml38b9/ajIge3CeN3OI6HQ=",
+      "dev": true
+    },
     "pkg-dir": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
@@ -7735,9 +7903,9 @@
       }
     },
     "pluralize": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
-      "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+      "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
       "dev": true
     },
     "pngjs": {
@@ -8391,26 +8559,6 @@
       "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
       "dev": true
     },
-    "pretty-format": {
-      "version": "19.0.0",
-      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-19.0.0.tgz",
-      "integrity": "sha1-VlMNMqy5ij+khRxOK503tCBoTIQ=",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^3.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        }
-      }
-    },
     "pretty-ms": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.0.1.tgz",
@@ -8421,6 +8569,24 @@
         "plur": "^2.1.2"
       }
     },
+    "prettyjson": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz",
+      "integrity": "sha1-/P+rQdGcq0365eV15kJGYZsS0ok=",
+      "dev": true,
+      "requires": {
+        "colors": "^1.1.2",
+        "minimist": "^1.2.0"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
     "printf": {
       "version": "0.2.5",
       "resolved": "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz",
@@ -8477,6 +8643,16 @@
       "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
       "dev": true
     },
+    "pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
     "punycode": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
@@ -8540,12 +8716,6 @@
         }
       }
     },
-    "range-parser": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz",
-      "integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=",
-      "dev": true
-    },
     "rax": {
       "version": "0.4.20",
       "resolved": "https://registry.npmjs.org/rax/-/rax-0.4.20.tgz",
@@ -8558,6 +8728,26 @@
         "universal-env": "^0.4.20"
       }
     },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dev": true,
+      "requires": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
     "read-only-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
@@ -8599,27 +8789,6 @@
         }
       }
     },
-    "read-pkg": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
-      "dev": true,
-      "requires": {
-        "load-json-file": "^1.0.0",
-        "normalize-package-data": "^2.3.2",
-        "path-type": "^1.0.0"
-      }
-    },
-    "read-pkg-up": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
-      "dev": true,
-      "requires": {
-        "find-up": "^1.0.0",
-        "read-pkg": "^1.0.0"
-      }
-    },
     "readable-stream": {
       "version": "1.1.14",
       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
@@ -8675,16 +8844,11 @@
         }
       }
     },
-    "readline2": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
-      "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
-      "dev": true,
-      "requires": {
-        "code-point-at": "^1.0.0",
-        "is-fullwidth-code-point": "^1.0.0",
-        "mute-stream": "0.0.5"
-      }
+    "readline-sync": {
+      "version": "1.4.10",
+      "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
+      "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==",
+      "dev": true
     },
     "rechoir": {
       "version": "0.6.2",
@@ -8790,6 +8954,25 @@
         "regjsparser": "^0.1.4"
       }
     },
+    "registry-auth-token": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
+      "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
+      "dev": true,
+      "requires": {
+        "rc": "^1.1.6",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "registry-url": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
+      "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
+      "dev": true,
+      "requires": {
+        "rc": "^1.0.1"
+      }
+    },
     "regjsgen": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
@@ -8976,24 +9159,12 @@
         "throttleit": "^1.0.0"
       }
     },
-    "require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-      "dev": true
-    },
     "require-from-string": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz",
       "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=",
       "dev": true
     },
-    "require-main-filename": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
-      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
-      "dev": true
-    },
     "require-uncached": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
@@ -9038,13 +9209,13 @@
       "dev": true
     },
     "restore-cursor": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
-      "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
       "dev": true,
       "requires": {
-        "exit-hook": "^1.0.0",
-        "onetime": "^1.0.0"
+        "onetime": "^2.0.0",
+        "signal-exit": "^3.0.2"
       }
     },
     "ret": {
@@ -9053,10 +9224,16 @@
       "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
       "dev": true
     },
+    "retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
+      "dev": true
+    },
     "rfc6902": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/rfc6902/-/rfc6902-1.3.0.tgz",
-      "integrity": "sha1-hbLGnELc8RYIJDe5gpqWJEa0xKU=",
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/rfc6902/-/rfc6902-3.0.4.tgz",
+      "integrity": "sha512-OnzreaZXrwT5w2ikKXWr5QcuI7NZpL+J3hIkAwozjOnKVUL7fPsB8Vcmu8YBiiou1/r3V0Jc0T1uQDyfAPvLzA==",
       "dev": true
     },
     "right-align": {
@@ -9558,12 +9735,12 @@
       }
     },
     "run-async": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
-      "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
       "dev": true,
       "requires": {
-        "once": "^1.3.0"
+        "is-promise": "^2.1.0"
       }
     },
     "runtime-shared": {
@@ -9611,47 +9788,6 @@
       "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==",
       "dev": true
     },
-    "sane": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/sane/-/sane-1.5.0.tgz",
-      "integrity": "sha1-pK3q52TQSGIeyyfV+ez1ExAZOfM=",
-      "dev": true,
-      "requires": {
-        "anymatch": "^1.3.0",
-        "exec-sh": "^0.2.0",
-        "fb-watchman": "^1.8.0",
-        "minimatch": "^3.0.2",
-        "minimist": "^1.1.1",
-        "walker": "~1.0.5",
-        "watch": "~0.10.0"
-      },
-      "dependencies": {
-        "bser": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz",
-          "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=",
-          "dev": true,
-          "requires": {
-            "node-int64": "^0.4.0"
-          }
-        },
-        "fb-watchman": {
-          "version": "1.9.2",
-          "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz",
-          "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=",
-          "dev": true,
-          "requires": {
-            "bser": "1.0.2"
-          }
-        },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        }
-      }
-    },
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
@@ -9669,53 +9805,104 @@
       "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
       "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
     },
-    "send": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/send/-/send-0.0.3.tgz",
-      "integrity": "sha1-TV+EPt+dZdrDHIpdJnLBeey2cYQ=",
+    "serve": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/serve/-/serve-7.1.3.tgz",
+      "integrity": "sha512-XNDcJbtFWn6dc6U46/kq6LkXFuk33MqA+FZZdWJ/Y4ttEV1P7oD+mVNcKS9DYuXQEnKgqLH36Qv88mSvLxQPcw==",
       "dev": true,
       "requires": {
-        "debug": "*",
-        "fresh": "0.1.0",
-        "mime": "1.2.6",
-        "range-parser": "0.0.4"
+        "@zeit/schemas": "1.1.2",
+        "ajv": "6.5.0",
+        "arg": "2.0.0",
+        "chalk": "2.4.1",
+        "serve-handler": "2.3.15",
+        "update-check": "1.5.2"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.5.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.0.tgz",
+          "integrity": "sha512-VDUX1oSajablmiyFyED9L1DFndg0P9h7p1F+NO8FkIzei6EPrR6Zu1n18rd5P8PqaSRd/FrWv3G1TVBqpM83gA==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^2.0.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.3.0",
+            "uri-js": "^4.2.1"
+          }
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "fast-deep-equal": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+          "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "serve-handler": {
+      "version": "2.3.15",
+      "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-2.3.15.tgz",
+      "integrity": "sha512-GBJtA2DPAJzo+6bdYeXdM7Wwt676kh1s64yi9k+jxlNTbezC7MZJa3csInGOG9VRFKr9r3+xZwyCLNcd8my33Q==",
+      "dev": true,
+      "requires": {
+        "bytes": "3.0.0",
+        "fast-url-parser": "1.1.3",
+        "glob-slasher": "1.0.1",
+        "mime": "2.3.1",
+        "minimatch": "3.0.4",
+        "path-is-inside": "1.0.2",
+        "path-to-regexp": "2.2.1"
       },
       "dependencies": {
         "mime": {
-          "version": "1.2.6",
-          "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.6.tgz",
-          "integrity": "sha1-sfhsdowCX6h7SAdfFwnyiuryA2U=",
+          "version": "2.3.1",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz",
+          "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==",
+          "dev": true
+        },
+        "path-to-regexp": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
+          "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==",
           "dev": true
         }
       }
     },
-    "serve": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/serve/-/serve-1.4.0.tgz",
-      "integrity": "sha1-41885rQlhrfz3te1sKMaAbsOEAU=",
-      "dev": true,
-      "requires": {
-        "commander": "0.6.1",
-        "connect": "2.3.x",
-        "jade": "*",
-        "less-middleware": "*",
-        "stylus": "*"
-      },
-      "dependencies": {
-        "commander": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz",
-          "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=",
-          "dev": true
-        }
-      }
-    },
-    "set-blocking": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
-      "dev": true
-    },
     "set-immediate-shim": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
@@ -9723,9 +9910,9 @@
       "dev": true
     },
     "set-value": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
-      "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
       "dev": true,
       "requires": {
         "extend-shallow": "^2.0.1",
@@ -9742,6 +9929,21 @@
           "requires": {
             "is-extendable": "^0.1.0"
           }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+          "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+          "dev": true,
+          "requires": {
+            "isobject": "^3.0.1"
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true
         }
       }
     },
@@ -9897,10 +10099,13 @@
       "dev": true
     },
     "slice-ansi": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
-      "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
-      "dev": true
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
+      "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0"
+      }
     },
     "snapdragon": {
       "version": "0.8.2",
@@ -10068,36 +10273,10 @@
       "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
       "dev": true
     },
-    "spdx-correct": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
-      "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
-      "dev": true,
-      "requires": {
-        "spdx-expression-parse": "^3.0.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-exceptions": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
-      "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==",
-      "dev": true
-    },
-    "spdx-expression-parse": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
-      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
-      "dev": true,
-      "requires": {
-        "spdx-exceptions": "^2.1.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-license-ids": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
-      "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==",
+    "split-on-first": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
+      "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
       "dev": true
     },
     "split-string": {
@@ -10359,14 +10538,30 @@
       "dev": true
     },
     "string-width": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
       "dev": true,
       "requires": {
-        "code-point-at": "^1.0.0",
-        "is-fullwidth-code-point": "^1.0.0",
-        "strip-ansi": "^3.0.0"
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
       }
     },
     "string_decoder": {
@@ -10389,12 +10584,6 @@
         "ansi-regex": "^2.0.0"
       }
     },
-    "strip-bom": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-      "dev": true
-    },
     "strip-eof": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
@@ -10402,9 +10591,9 @@
       "dev": true
     },
     "strip-json-comments": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
-      "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
       "dev": true
     },
     "style-unit": {
@@ -10412,51 +10601,6 @@
       "resolved": "https://registry.npmjs.org/style-unit/-/style-unit-0.4.20.tgz",
       "integrity": "sha1-x/Nrgz+V3y9Zj5TcLVQXwIqtD8Q="
     },
-    "stylus": {
-      "version": "0.54.5",
-      "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz",
-      "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=",
-      "dev": true,
-      "requires": {
-        "css-parse": "1.7.x",
-        "debug": "*",
-        "glob": "7.0.x",
-        "mkdirp": "0.5.x",
-        "sax": "0.5.x",
-        "source-map": "0.1.x"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.0.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
-          "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.2",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "sax": {
-          "version": "0.5.8",
-          "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
-          "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.1.43",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
-          "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
-          "dev": true,
-          "requires": {
-            "amdefine": ">=0.0.4"
-          }
-        }
-      }
-    },
     "subarg": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
@@ -10483,6 +10627,41 @@
         "has-flag": "^1.0.0"
       }
     },
+    "supports-hyperlinks": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz",
+      "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^2.0.0",
+        "supports-color": "^5.0.0"
+      },
+      "dependencies": {
+        "has-flag": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+          "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          },
+          "dependencies": {
+            "has-flag": {
+              "version": "3.0.0",
+              "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+              "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+              "dev": true
+            }
+          }
+        }
+      }
+    },
     "svgo": {
       "version": "0.7.2",
       "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
@@ -10510,12 +10689,6 @@
         }
       }
     },
-    "symbol-tree": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
-      "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
-      "dev": true
-    },
     "sync-exec": {
       "version": "0.6.2",
       "resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz",
@@ -10533,58 +10706,52 @@
       }
     },
     "table": {
-      "version": "3.8.3",
-      "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
-      "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
+      "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
       "dev": true,
       "requires": {
-        "ajv": "^4.7.0",
-        "ajv-keywords": "^1.0.0",
-        "chalk": "^1.1.1",
-        "lodash": "^4.0.0",
-        "slice-ansi": "0.0.4",
-        "string-width": "^2.0.0"
+        "ajv": "^5.2.3",
+        "ajv-keywords": "^2.1.0",
+        "chalk": "^2.1.0",
+        "lodash": "^4.17.4",
+        "slice-ansi": "1.0.0",
+        "string-width": "^2.1.1"
       },
       "dependencies": {
-        "ajv": {
-          "version": "4.11.8",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
-          "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
           "dev": true,
           "requires": {
-            "co": "^4.6.0",
-            "json-stable-stringify": "^1.0.1"
+            "color-convert": "^1.9.0"
           }
         },
-        "ansi-regex": {
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "has-flag": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
           "dev": true
         },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
           "dev": true,
           "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^3.0.0"
+            "has-flag": "^3.0.0"
           }
         }
       }
@@ -10621,295 +10788,6 @@
         }
       }
     },
-    "test-exclude": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz",
-      "integrity": "sha512-qpqlP/8Zl+sosLxBcVKl9vYy26T9NPalxSzzCP/OY6K7j938ui2oKgo+kRZYfxAeIpLqpbVnsHq1tyV70E4lWQ==",
-      "dev": true,
-      "requires": {
-        "arrify": "^1.0.1",
-        "micromatch": "^3.1.8",
-        "object-assign": "^4.1.0",
-        "read-pkg-up": "^1.0.1",
-        "require-main-filename": "^1.0.1"
-      },
-      "dependencies": {
-        "arr-diff": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
-          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
-          "dev": true
-        },
-        "array-unique": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
-          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
-          "dev": true
-        },
-        "braces": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
-          "dev": true,
-          "requires": {
-            "arr-flatten": "^1.1.0",
-            "array-unique": "^0.3.2",
-            "extend-shallow": "^2.0.1",
-            "fill-range": "^4.0.0",
-            "isobject": "^3.0.1",
-            "repeat-element": "^1.1.2",
-            "snapdragon": "^0.8.1",
-            "snapdragon-node": "^2.0.1",
-            "split-string": "^3.0.2",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "expand-brackets": {
-          "version": "2.1.4",
-          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
-          "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
-          "dev": true,
-          "requires": {
-            "debug": "^2.3.3",
-            "define-property": "^0.2.5",
-            "extend-shallow": "^2.0.1",
-            "posix-character-classes": "^0.1.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "define-property": {
-              "version": "0.2.5",
-              "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-              "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-              "dev": true,
-              "requires": {
-                "is-descriptor": "^0.1.0"
-              }
-            },
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            },
-            "is-accessor-descriptor": {
-              "version": "0.1.6",
-              "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
-              "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
-              "dev": true,
-              "requires": {
-                "kind-of": "^3.0.2"
-              },
-              "dependencies": {
-                "kind-of": {
-                  "version": "3.2.2",
-                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-                  "dev": true,
-                  "requires": {
-                    "is-buffer": "^1.1.5"
-                  }
-                }
-              }
-            },
-            "is-data-descriptor": {
-              "version": "0.1.4",
-              "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
-              "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
-              "dev": true,
-              "requires": {
-                "kind-of": "^3.0.2"
-              },
-              "dependencies": {
-                "kind-of": {
-                  "version": "3.2.2",
-                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-                  "dev": true,
-                  "requires": {
-                    "is-buffer": "^1.1.5"
-                  }
-                }
-              }
-            },
-            "is-descriptor": {
-              "version": "0.1.6",
-              "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
-              "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
-              "dev": true,
-              "requires": {
-                "is-accessor-descriptor": "^0.1.6",
-                "is-data-descriptor": "^0.1.4",
-                "kind-of": "^5.0.0"
-              }
-            },
-            "kind-of": {
-              "version": "5.1.0",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-              "dev": true
-            }
-          }
-        },
-        "extglob": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
-          "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
-          "dev": true,
-          "requires": {
-            "array-unique": "^0.3.2",
-            "define-property": "^1.0.0",
-            "expand-brackets": "^2.1.4",
-            "extend-shallow": "^2.0.1",
-            "fragment-cache": "^0.2.1",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "define-property": {
-              "version": "1.0.0",
-              "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-              "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-              "dev": true,
-              "requires": {
-                "is-descriptor": "^1.0.0"
-              }
-            },
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "fill-range": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1",
-            "to-regex-range": "^2.1.0"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        },
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "3.1.10",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-          "dev": true,
-          "requires": {
-            "arr-diff": "^4.0.0",
-            "array-unique": "^0.3.2",
-            "braces": "^2.3.1",
-            "define-property": "^2.0.2",
-            "extend-shallow": "^3.0.2",
-            "extglob": "^2.0.4",
-            "fragment-cache": "^0.2.1",
-            "kind-of": "^6.0.2",
-            "nanomatch": "^1.2.9",
-            "object.pick": "^1.3.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.2"
-          }
-        }
-      }
-    },
     "text-encoding": {
       "version": "0.6.4",
       "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz",
@@ -10994,12 +10872,6 @@
         "os-tmpdir": "~1.0.2"
       }
     },
-    "tmpl": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
-      "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=",
-      "dev": true
-    },
     "to-arraybuffer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -11068,11 +10940,31 @@
         "punycode": "^1.4.1"
       }
     },
+    "toxic": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toxic/-/toxic-1.0.1.tgz",
+      "integrity": "sha512-WI3rIGdcaKULYg7KVoB0zcjikqvcYYvcuT6D89bFPz2rVR0Rl0PK6x8/X62rtdLtBKIE985NzVf/auTtGegIIg==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.10"
+      }
+    },
     "tr46": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
-      "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
-      "dev": true
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+      "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+          "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+          "dev": true
+        }
+      }
     },
     "trim-right": {
       "version": "1.0.1",
@@ -11209,38 +11101,15 @@
       }
     },
     "union-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
-      "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
       "dev": true,
       "requires": {
         "arr-union": "^3.1.0",
         "get-value": "^2.0.6",
         "is-extendable": "^0.1.1",
-        "set-value": "^0.4.3"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "set-value": {
-          "version": "0.4.3",
-          "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
-          "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-extendable": "^0.1.1",
-            "is-plain-object": "^2.0.1",
-            "to-object-path": "^0.3.0"
-          }
-        }
+        "set-value": "^2.0.1"
       }
     },
     "uniq": {
@@ -11260,6 +11129,25 @@
       "resolved": "https://registry.npmjs.org/universal-env/-/universal-env-0.4.20.tgz",
       "integrity": "sha1-aVoXaccMGnFDNQllZnQYQfiQlyY="
     },
+    "universal-url": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/universal-url/-/universal-url-2.0.0.tgz",
+      "integrity": "sha512-3DLtXdm/G1LQMCnPj+Aw7uDoleQttNHp2g5FnNQKR6cP6taNWS1b/Ehjjx4PVyvejKi3TJyu8iBraKM4q3JQPg==",
+      "dev": true,
+      "requires": {
+        "hasurl": "^1.0.0",
+        "whatwg-url": "^7.0.0"
+      }
+    },
+    "universal-user-agent": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz",
+      "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==",
+      "dev": true,
+      "requires": {
+        "os-name": "^3.1.0"
+      }
+    },
     "unset-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
@@ -11312,6 +11200,33 @@
         }
       }
     },
+    "update-check": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz",
+      "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==",
+      "dev": true,
+      "requires": {
+        "registry-auth-token": "3.3.2",
+        "registry-url": "3.1.0"
+      }
+    },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+          "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+          "dev": true
+        }
+      }
+    },
     "urix": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
@@ -11348,15 +11263,6 @@
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
       "dev": true
     },
-    "user-home": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
-      "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
-      "dev": true,
-      "requires": {
-        "os-homedir": "^1.0.0"
-      }
-    },
     "util": {
       "version": "0.10.4",
       "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
@@ -11377,16 +11283,6 @@
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
       "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
     },
-    "validate-npm-package-license": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
-      "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
-      "dev": true,
-      "requires": {
-        "spdx-correct": "^3.0.0",
-        "spdx-expression-parse": "^3.0.0"
-      }
-    },
     "vargs": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/vargs/-/vargs-0.1.0.tgz",
@@ -11424,12 +11320,6 @@
         "indexof": "0.0.1"
       }
     },
-    "voca": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/voca/-/voca-1.4.0.tgz",
-      "integrity": "sha512-8Xz4H3vhYRGbFupLtl6dHwMx0ojUcjt0HYkqZ9oBCfipd/5mD7Md58m2/dq7uPuZU/0T3Gb1m66KS9jn+I+14Q==",
-      "dev": true
-    },
     "vue": {
       "version": "2.4.3",
       "resolved": "https://registry.npmjs.org/vue/-/vue-2.4.3.tgz",
@@ -11532,21 +11422,6 @@
       "integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==",
       "dev": true
     },
-    "walker": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
-      "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=",
-      "dev": true,
-      "requires": {
-        "makeerror": "1.0.x"
-      }
-    },
-    "watch": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz",
-      "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=",
-      "dev": true
-    },
     "watchpack": {
       "version": "0.2.9",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-0.2.9.tgz",
@@ -12040,23 +11915,6 @@
         "webdriver-client": "^1.0.17"
       }
     },
-    "whatwg-encoding": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz",
-      "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==",
-      "dev": true,
-      "requires": {
-        "iconv-lite": "0.4.19"
-      },
-      "dependencies": {
-        "iconv-lite": {
-          "version": "0.4.19",
-          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
-          "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==",
-          "dev": true
-        }
-      }
-    },
     "whatwg-fetch": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
@@ -12064,21 +11922,14 @@
       "dev": true
     },
     "whatwg-url": {
-      "version": "4.8.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz",
-      "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+      "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
       "dev": true,
       "requires": {
-        "tr46": "~0.0.3",
-        "webidl-conversions": "^3.0.0"
-      },
-      "dependencies": {
-        "webidl-conversions": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
-          "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
-          "dev": true
-        }
+        "lodash.sortby": "^4.7.0",
+        "tr46": "^1.0.1",
+        "webidl-conversions": "^4.0.2"
       }
     },
     "whet.extend": {
@@ -12096,43 +11947,27 @@
         "isexe": "^2.0.0"
       }
     },
-    "which-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
-      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
-      "dev": true
-    },
     "window-size": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
       "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
       "dev": true
     },
+    "windows-release": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.2.0.tgz",
+      "integrity": "sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==",
+      "dev": true,
+      "requires": {
+        "execa": "^1.0.0"
+      }
+    },
     "wordwrap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
       "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
       "dev": true
     },
-    "worker-farm": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz",
-      "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==",
-      "dev": true,
-      "requires": {
-        "errno": "~0.1.7"
-      }
-    },
-    "wrap-ansi": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
-      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
-      "dev": true,
-      "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1"
-      }
-    },
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -12164,12 +11999,6 @@
         "xutil": "~1.0.0"
       }
     },
-    "xml-name-validator": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
-      "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
-      "dev": true
-    },
     "xml-writer": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/xml-writer/-/xml-writer-1.7.0.tgz",
@@ -12268,12 +12097,6 @@
         }
       }
     },
-    "y18n": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
-      "dev": true
-    },
     "yallist": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
@@ -12292,23 +12115,6 @@
         "window-size": "0.1.0"
       }
     },
-    "yargs-parser": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
-      "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
-      "dev": true,
-      "requires": {
-        "camelcase": "^3.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true
-        }
-      }
-    },
     "yauzl": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
diff --git a/package.json b/package.json
index 28cb05c..9c0de09 100644
--- a/package.json
+++ b/package.json
@@ -99,7 +99,7 @@
     "css-loader": "^0.26.1",
     "danger": "^9.0.0",
     "dateformat": "^2.0.0",
-    "eslint": "^2.11.1",
+    "eslint": "^4.18.2",
     "eslint-plugin-flowtype": "^2.40.1",
     "fs-extra": "^2.0.0",
     "github": "^9.2.0",
@@ -120,7 +120,7 @@
     "rollup-plugin-replace": "^2.0.0",
     "rollup-plugin-uglify": "^2.0.1",
     "selenium-server": "2.53.1",
-    "serve": "^1.4.0",
+    "serve": "^7.1.3",
     "shelljs": "^0.7.8",
     "sinon": "^2.1.0",
     "sinon-chai": "^2.8.0",
diff --git a/scripts/build_from_source.sh b/scripts/build_from_source.sh
index de67740..30b89af 100755
--- a/scripts/build_from_source.sh
+++ b/scripts/build_from_source.sh
@@ -17,7 +17,7 @@
 # under the License.
 
 # This script is used to build weex from source, One may invoke this script by 
-# scripts/build_from_source.sh $NDK13_dir $NDK_16dir
+# scripts/build_from_source.sh 
 
 set -e
 if [ ! -f scripts/build_from_source.sh ];then
@@ -43,60 +43,16 @@
 cp dist/weex-rax.min.js pre-build/weex-rax-api.js
 
 # Build android_sdk
-if [ -d "android_sdk" ]
+cd android/
+if [ ! -d "gradle" ]
 then
-    git clone -b 0.23 --depth=1 git@github.com:alibaba/weex_js_engine.git
-    old_path=$PATH
-    export ANDROID_NDK=$1
-    export PATH=$1:$PATH
-    cd weex_js_engine/
-
-    sh build.jsc.sh
-    cp libWTF.so libJavaScriptCore.so ../android_sdk/libs/armeabi
-    cp libWTF.so libJavaScriptCore.so ../android_sdk/libs/armeabi-v7a
-
-    mkdir -p ../weex_core/Source/libs/armeabi
-    cp libWTF.so libJavaScriptCore.so ../weex_core/Source/libs/armeabi
-    mkdir -p ../weex_core/Source/libs/armeabi-v7a
-    cp libWTF.so libJavaScriptCore.so ../weex_core/Source/libs/armeabi-v7a
-
-    rm -rf build32
-    sh build.jsc.sh -t x86
-    cp libWTF.so libJavaScriptCore.so ../android_sdk/libs/x86
-    mkdir -p ../weex_core/Source/libs/x86
-    cp libWTF.so libJavaScriptCore.so ../weex_core/Source/libs/x86
-
-    PATH=$old_path
-    export ANDROID_NDK=$2
-    cd ..
-
-    gradle wrapper --gradle-version 4.4
-    echo 'include ":android_sdk"'>settings.gradle
-    echo "ndk.dir=$2">local.properties
-
-    ./gradlew :android_sdk:clean :android_sdk:assembleRelease -PignoreVersionCheck="true" -PbuildRuntimeApi=true
-
-    cp android_sdk/.externalNativeBuild/cmake/release/armeabi/Source/android/jsengine/libweexjsb.so android_sdk/libs/armeabi
-    cp android_sdk/.externalNativeBuild/cmake/release/armeabi/Source/android/jsengine/libweexjst.so android_sdk/libs/armeabi
-    cp android_sdk/.externalNativeBuild/cmake/release/armeabi-v7a/Source/android/jsengine/libweexjsb.so android_sdk/libs/armeabi-v7a
-    cp android_sdk/.externalNativeBuild/cmake/release/armeabi-v7a/Source/android/jsengine/libweexjst.so android_sdk/libs/armeabi-v7a
-    cp android_sdk/.externalNativeBuild/cmake/release/x86/Source/android/jsengine/libweexjsb.so android_sdk/libs/x86
-    cp android_sdk/.externalNativeBuild/cmake/release/x86/Source/android/jsengine/libweexjst.so android_sdk/libs/x86
-
-else
-    cd android/
-    ./gradlew :playground:clean :playground:assemble
-    cd ..
+    gradle wrapper --gradle-version 4.10.1
 fi
 
+./gradlew :weex_sdk:clean :weex_sdk:assembleRelease -PignoreVersionCheck="true" -PbuildRuntimeApi=true -PapachePackageName="true"
+cd ..
+
 # Build iOS sdk
-if [ -d "ios_sdk" ]
-then
-    xcodebuild -project ios_sdk/WeexSDK.xcodeproj -scheme WeexSDK_MTL
-else
-    cd ios
-    xcodebuild -project sdk/WeexSDK.xcodeproj -scheme WeexSDK_MTL
-    cd ..
-fi
+xcodebuild -project ios/sdk/WeexSDK.xcodeproj -scheme WeexSDK_MTL
 
 echo "Weex SDK Build completed."
diff --git a/scripts/generate_apache_source.sh b/scripts/generate_apache_source.sh
index d339337..9098be3 100755
--- a/scripts/generate_apache_source.sh
+++ b/scripts/generate_apache_source.sh
@@ -9,33 +9,4 @@
 
 rm -rf $dest
 mkdir $dest
-rsync -r --include-from=scripts/release_files.rules ./ $dest
-
-SED_CMD=sed
-if [ $(uname) == 'Darwin' ]; then
-  SED_CMD=/usr/bin/sed
-fi
-
-#repackage
-find $dest/android/sdk -type f \( -name '*.java' -o -name 'AndroidManifest.xml' -o -name 'proguard-rules.pro' \) -exec $SED_CMD -i '' 's/com\.taobao\.weex/org\.apache\.weex/g' {} \;
-find $dest/ios/sdk -type f \( -name 'project.pbxproj' -o -name '*.h' -o -name '*.m' -o -name '*.mm' \) -exec $SED_CMD -i '' 's/com\.taobao\.weex/org\.apache\.weex/g' {} \;
-
-mkdir -p $dest/android/sdk/src/main/java/org
-mkdir -p $dest/android/sdk/src/main/java/org/apache
-mv $dest/android/sdk/src/main/java/com/taobao $dest/android/sdk/src/main/java/org/apache
-rm -rf $dest/android/sdk/src/main/java/com
-
-mkdir -p $dest/android/sdk/src/test/java/org
-mkdir -p $dest/android/sdk/src/test/java/org/apache
-mv $dest/android/sdk/src/test/java/com/taobao $dest/android/sdk/src/test/java/org/apache
-rm -rf $dest/android/sdk/src/test/java/com
-
-mv $dest/ios/sdk $dest/ios_sdk
-mv $dest/android/sdk $dest/android_sdk
-$SED_CMD -i '' 's/\.\.\/\.\.\/weex_core/\.\.\/weex_core/g' $dest/android_sdk/build.gradle $dest/ios_sdk/WeexSDK.xcodeproj/project.pbxproj
-$SED_CMD -i '' 's/\.\.\/\.\.\/pre-build/\.\.\/pre-build/g' $dest/android_sdk/build.gradle $dest/ios_sdk/WeexSDK.xcodeproj/project.pbxproj
-[ -d "$dest/ios_sdk/build" ] && rm -rf "$dest/ios_sdk/build"
-mv $dest/android/build.gradle $dest/build.gradle
-rm -rf $dest/android $dest/ios
-
-rm -rf $dest/android_sdk/gradle
+rsync -r --include-from=scripts/release_files.rules ./ $dest
\ No newline at end of file
diff --git a/scripts/publish_release_candidate.sh b/scripts/publish_release_candidate.sh
index ef7465e..dba1748 100755
--- a/scripts/publish_release_candidate.sh
+++ b/scripts/publish_release_candidate.sh
@@ -36,5 +36,5 @@
 mkdir -p "$TMPDIR""weex_release_candidate/""$1/$2"
 cp "apache-weex-incubating-$1-$2-src.tar.gz" "apache-weex-incubating-$1-$2-src.tar.gz.asc" "apache-weex-incubating-$1-$2-src.tar.gz.sha512" "$TMPDIR""weex_release_candidate/""$1/$2"
 cd "$TMPDIR""weex_release_candidate"
-svn add "$1/$2"
-svn commit -m "$4"
\ No newline at end of file
+svn add . --force
+svn commit -m "Update for $1-$2"
diff --git a/scripts/publish_release_official.sh b/scripts/publish_release_official.sh
index 3d147a2..0752946 100755
--- a/scripts/publish_release_official.sh
+++ b/scripts/publish_release_official.sh
@@ -36,23 +36,26 @@
 sed -i '' 's/^/* /' commit-history.log
 sed -i '' -e '1i \
 # Detail Commit' commit-history.log
-cat CHANGELOG.md commit-history.log > RELEASE_NOTE.md
+cat DISCLAIMER CHANGELOG.md commit-history.log > RELEASE_NOTE.md
 
 echo "Publish source file to Apache SVN server"
 if [ ! -d "${TMPDIR}weex_release" ]
 then
     svn checkout https://dist.apache.org/repos/dist/release/incubator/weex/ "${TMPDIR}weex_release"
 fi
+cd "${TMPDIR}weex_release"
+export svn_dir=`ls -C -d */` ; svn delete $svn_dir
 mkdir -p "${TMPDIR}weex_release/${1}" && cd "$_"
 curl "https://dist.apache.org/repos/dist/dev/incubator/weex/${1}/${2}/apache-weex-incubating-${1}-${2}-src.tar.gz" -o "apache-weex-incubating-${1}-src.tar.gz"
 curl "https://dist.apache.org/repos/dist/dev/incubator/weex/${1}/${2}/apache-weex-incubating-${1}-${2}-src.tar.gz.asc" -o "apache-weex-incubating-${1}-src.tar.gz.asc"
 curl "https://dist.apache.org/repos/dist/dev/incubator/weex/${1}/${2}/apache-weex-incubating-${1}-${2}-src.tar.gz.sha512" -o "apache-weex-incubating-${1}-src.tar.gz.sha512"
 cd ..
-svn add "$1"
+svn add . --force
 svn commit -m "Release ${1}"
 
 echo "Push Git Tag to Github Repo"
-git tag -a -F "RELEASE_NOTE.md" "$1"
+pushd +3
+git tag -a -F "RELEASE_NOTE.md" "$1" "$1-$2"
 git push "$4" "$1"
 
 echo "Publish Github Release"
@@ -62,6 +65,7 @@
 
 echo "Publish Android JCenter Release"
 cd android
-./gradlew clean install bintray -PbuildRuntimeApi=true -PignoreVersionCheck="true"  -PweexVersion="$1" -PbintrayUser=alibabaweex -PbintrayApiKey="$6" 
+./gradlew :weex_sdk:clean :weex_sdk:install :weex_sdk:bintray -PgroupId="org.apache.weex" -PartifactName="sdk" -PapachePackageName="true" -PvcsTag="$1" -PunbundlingJSC="true" -PbuildRuntimeApi=true -PignoreVersionCheck="true" -PweexVersion="$1" -PbintrayUser=weex -PbintrayApiKey="$6" 
+./gradlew :weex_sdk:install :weex_sdk:bintray -PgroupId="org.apache.weex" -PartifactName="sdk_legacy" -PapachePackageName="false" -PvcsTag="$1" -PunbundlingJSC="true" -PbuildRuntimeApi=true -PignoreVersionCheck="true" -PweexVersion="$1" -PbintrayUser=weex -PbintrayApiKey="$6" 
 
 # Publish iOS to Cocoapods
\ No newline at end of file
diff --git a/scripts/release_files.rules b/scripts/release_files.rules
index 02e8b0f..0049f0a 100644
--- a/scripts/release_files.rules
+++ b/scripts/release_files.rules
@@ -29,6 +29,7 @@
 + /.eslintignore
 + /.babelrc
 + /src
++ /.rat-excludes
 - /src/h5-render/dist/index.js
 - /src/h5-render/node_modules
 - /src/js-framework/node_modules
@@ -53,22 +54,20 @@
 - weex_core/Source/base/android/jniprebuild/jni_files
 - weex_core/Source/base/android/jniprebuild/jni_generator.py
 - weex_core/Source/base/android/jniprebuild/prebuild.sh
-+ /weex_core/Source/include/JavaScriptCore/API/
-+ /weex_core/Source/include/JavaScriptCore/API/**
-+ /weex_core/Source/include/JavaScriptCore/ForwardingHeaders/
-+ /weex_core/Source/include/JavaScriptCore/ForwardingHeaders/JavaScriptCore/
-+ /weex_core/Source/include/JavaScriptCore/ForwardingHeaders/JavaScriptCore/**
-- /weex_core/Source/include/JavaScriptCore/**
+- /weex_core/Source/android/jsengine/dependence/
+- /weex_core/Source/include/JavaScriptCore/
 - /weex_core/Source/include/wtf/
+- /weex_core/Source/include/JSCHeaderNew/JavaScriptCore/
 + /weex_core
 + /weex_core/CMakeLists.txt
 + /weex_core/Source
 + /weex_core/Source/**
 
 ###### android #######
-+ /android
++ /android/
 + /android/build.gradle
-+ /android/sdk/
++ /android/settings.gradle
++ /android/license/***
 - /android/sdk/assets/*.js
 - /android/sdk/.gradle
 - /android/sdk/build
@@ -79,19 +78,25 @@
 - /android/sdk/.classpath
 - /android/sdk/.project
 - /android/sdk/weex_sdk.iml
-+ /android/sdk/**
+- /android/sdk/android-weex_sdk.iml
+- /android/sdk/weex-android-weex_sdk.iml
+- /android/sdk/.cxx
+- /android/sdk/src/legacyRelease
+- /android/sdk/src/main/jniLibs
++ /android/sdk/***
 
 ###### ios ###########
-+ /ios
-+ /ios/sdk/
++ /ios/
 - /ios/sdk/LICENSE
 - /ios/sdk/NOTICE
 - /ios/sdk/WeexSDK/Resources/main.js
-- ios/sdk/Products
+- /ios/sdk/Products
 - /ios/sdk/WeexSDK.xcodeproj/project.xcworkspace/xcuserdata
 - /ios/sdk/WeexSDK.xcodeproj/xcuserdata
 - /ios/sdk/WeexSDKTests/dependency
-+ /ios/sdk/**
+- /ios/sdk/build
+- /ios/playground
++ /ios/sdk/***
 
 ##### Others #######
 + /RELEASE_NOTE.md
diff --git a/test/scripts/util.js b/test/scripts/util.js
index 197858f..9267562 100644
--- a/test/scripts/util.js
+++ b/test/scripts/util.js
@@ -114,7 +114,7 @@
         return isIOS? iOSOpts : androidOpts;
     },
     getDeviceHost:function(){
-        return getIpAddress()+":12581";
+        return getIpAddress()+':'+ servePort;
     },
     getPage:function(name){
         let url
diff --git a/weex-playground b/weex-playground
index 1f536fa..75d1051 160000
--- a/weex-playground
+++ b/weex-playground
@@ -1 +1 @@
-Subproject commit 1f536fa83893520568bccdefffdeb469c7e957cf
+Subproject commit 75d10519cf4d05a2d133b07930aee3612f0cba3f
diff --git a/weex_core/.gitignore b/weex_core/.gitignore
index ba15c87..766f1a1 100644
--- a/weex_core/.gitignore
+++ b/weex_core/.gitignore
@@ -3,3 +3,5 @@
 build64/
 cmake-build-debug
 cscope.out
+
+/Source/include/JSCHeaderNew/JavaScriptCore
\ No newline at end of file
diff --git a/weex_core/Source/CMakeLists.txt b/weex_core/Source/CMakeLists.txt
index d1bb5fe..508aaea 100755
--- a/weex_core/Source/CMakeLists.txt
+++ b/weex_core/Source/CMakeLists.txt
@@ -42,7 +42,7 @@
 add_definitions(-DDEBUG=1)
 
 message("ANDROID_PROJECT_DIR:"${ANDROID_PROJECT_DIR})
-set(LOCAL_LIBRARIES_DIR ${ANDROID_PROJECT_DIR}/libs/${ANDROID_ABI})
+set(LOCAL_LIBRARIES_DIR ${ANDROID_PROJECT_DIR}/src/main/jniLibs/${ANDROID_ABI})
 
 if ("${ANDROID_ABI}" STREQUAL "x86")
     # todo
@@ -119,19 +119,14 @@
   ## add_subdirectory for subdirectory has a CMakeLists.txt
   add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third_party/IPC)
 
-
-  message("check build jsc BUILD_RUNTIME_API flag: ${BUILD_RUNTIME_API}")
-  if ("${BUILD_RUNTIME_API}" STREQUAL "true")
-      add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/js_runtime)
-      message("cmake build jsApi for runtime")
+  if (DEFINED BUILD_RUNTIME_API)
+    message("Variable BUILD_RUNTIME_API is defined with value: ${BUILD_RUNTIME_API}")
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/js_runtime)
   else()
-      add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/android/jsengine)
-      message("cmake build jsApi for jsc")
+    message("Variable BUILD_RUNTIME_API is not defined")
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/android/jsengine)
   endif()
 
-
-
-
   ## include_directories for include head file
   include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/IPC)
 
diff --git a/weex_core/Source/WXBridge_jni.h b/weex_core/Source/WXBridge_jni.h
index 685f9f5..b889289 100644
--- a/weex_core/Source/WXBridge_jni.h
+++ b/weex_core/Source/WXBridge_jni.h
@@ -23,7 +23,7 @@
 // This file is autogenerated by
 //     base/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/bridge/WXBridge
+//     org/apache/weex/bridge/WXBridge
 
 #ifndef com_taobao_weex_bridge_WXBridge_JNI
 #define com_taobao_weex_bridge_WXBridge_JNI
@@ -34,7 +34,7 @@
 
 // Step 1: forward declarations.
 namespace {
-const char kWXBridgeClassPath[] = "com/taobao/weex/bridge/WXBridge";
+const char kWXBridgeClassPath[] = "org/apache/weex/bridge/WXBridge";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_WXBridge_clazz = NULL;
 #define WXBridge_clazz(env) g_WXBridge_clazz
@@ -915,7 +915,7 @@
 "Ljava/lang/String;"
 "J"
 ")"
-"Lcom/taobao/weex/layout/ContentBoxMeasurement;",
+"Lorg/apache/weex/layout/ContentBoxMeasurement;",
       &g_WXBridge_getMeasurementFunc);
 
   jobject ret =
@@ -957,7 +957,7 @@
     { "nativeInitFrameworkEnv",
 "("
 "Ljava/lang/String;"
-"Lcom/taobao/weex/bridge/WXParams;"
+"Lorg/apache/weex/bridge/WXParams;"
 "Ljava/lang/String;"
 "Z"
 ")"
@@ -965,7 +965,7 @@
     { "nativeInitFramework",
 "("
 "Ljava/lang/String;"
-"Lcom/taobao/weex/bridge/WXParams;"
+"Lorg/apache/weex/bridge/WXParams;"
 ")"
 "I", reinterpret_cast<void*>(InitFramework) },
     { "nativeRefreshInstance",
@@ -973,7 +973,7 @@
 "Ljava/lang/String;"
 "Ljava/lang/String;"
 "Ljava/lang/String;"
-"[Lcom/taobao/weex/bridge/WXJSObject;"
+"[Lorg/apache/weex/bridge/WXJSObject;"
 ")"
 "V", reinterpret_cast<void*>(RefreshInstance) },
     { "nativeExecJS",
@@ -981,7 +981,7 @@
 "Ljava/lang/String;"
 "Ljava/lang/String;"
 "Ljava/lang/String;"
-"[Lcom/taobao/weex/bridge/WXJSObject;"
+"[Lorg/apache/weex/bridge/WXJSObject;"
 ")"
 "I", reinterpret_cast<void*>(ExecJS) },
     { "nativeExecJSService",
@@ -994,7 +994,7 @@
 "Ljava/lang/String;"
 "Ljava/lang/String;"
 "Ljava/lang/String;"
-"[Lcom/taobao/weex/bridge/WXJSObject;"
+"[Lorg/apache/weex/bridge/WXJSObject;"
 ")"
 "[B", reinterpret_cast<void*>(ExecJSWithResult) },
     { "nativeExecJSWithCallback",
@@ -1002,7 +1002,7 @@
 "Ljava/lang/String;"
 "Ljava/lang/String;"
 "Ljava/lang/String;"
-"[Lcom/taobao/weex/bridge/WXJSObject;"
+"[Lorg/apache/weex/bridge/WXJSObject;"
 "J"
 ")"
 "V", reinterpret_cast<void*>(ExecJSWithCallback) },
@@ -1011,7 +1011,7 @@
 "Ljava/lang/String;"
 "Ljava/lang/String;"
 "Ljava/lang/String;"
-"[Lcom/taobao/weex/bridge/WXJSObject;"
+"[Lorg/apache/weex/bridge/WXJSObject;"
 ")"
 "I", reinterpret_cast<void*>(CreateInstanceContext) },
     { "nativeDestoryInstance",
@@ -1019,7 +1019,7 @@
 "Ljava/lang/String;"
 "Ljava/lang/String;"
 "Ljava/lang/String;"
-"[Lcom/taobao/weex/bridge/WXJSObject;"
+"[Lorg/apache/weex/bridge/WXJSObject;"
 ")"
 "I", reinterpret_cast<void*>(DestoryInstance) },
     { "nativeExecJSOnInstance",
diff --git a/weex_core/Source/android/wrap/log_utils.cpp b/weex_core/Source/android/wrap/log_utils.cpp
index 1942259..0c432c0 100644
--- a/weex_core/Source/android/wrap/log_utils.cpp
+++ b/weex_core/Source/android/wrap/log_utils.cpp
@@ -27,7 +27,7 @@
 
 namespace WeexCore {
 
-const char kWXLogUtilsClassPath[] = "com/taobao/weex/utils/WXLogUtils";
+const char kWXLogUtilsClassPath[] = "org/apache/weex/utils/WXLogUtils";
 static jclass g_WXLogUtils_clazz = nullptr;
 
 static intptr_t g_WXLogUtils_d = 0;
diff --git a/weex_core/Source/android/wrap/wml_bridge.cpp b/weex_core/Source/android/wrap/wml_bridge.cpp
index f93dbfd..63741f8 100644
--- a/weex_core/Source/android/wrap/wml_bridge.cpp
+++ b/weex_core/Source/android/wrap/wml_bridge.cpp
@@ -189,7 +189,7 @@
 
 static JNINativeMethod gWMMethods[] = {
     {"nativeInitAppFramework",
-     "(Ljava/lang/String;Ljava/lang/String;[Lcom/taobao/weex/bridge/"
+     "(Ljava/lang/String;Ljava/lang/String;[Lorg/apache/weex/bridge/"
      "WXJSObject;)I",
      (void*)InitAppFramework},
     {"nativeCreateAppContext",
@@ -197,7 +197,7 @@
      (void*)CreateAppContext},
     {"nativeExecJsOnApp",
      "(Ljava/lang/String;Ljava/lang/String;"
-     "[Lcom/taobao/weex/bridge/WXJSObject;)I",
+     "[Lorg/apache/weex/bridge/WXJSObject;)I",
      (void*)ExecJsOnApp},
     {"nativeExecJsOnAppWithResult",
      "(Ljava/lang/String;Ljava/lang/String;"
diff --git a/weex_core/Source/android/wrap/wx_js_object.cpp b/weex_core/Source/android/wrap/wx_js_object.cpp
index 50a10dc..adceb5c 100644
--- a/weex_core/Source/android/wrap/wx_js_object.cpp
+++ b/weex_core/Source/android/wrap/wx_js_object.cpp
@@ -22,7 +22,7 @@
 #include "base/android/jni/android_jni.h"
 
 namespace WeexCore {
-const char kWXJSObjectClassPath[] = "com/taobao/weex/bridge/WXJSObject";
+const char kWXJSObjectClassPath[] = "org/apache/weex/bridge/WXJSObject";
 jclass g_WXJSObject_clazz = nullptr;
 
 jfieldID g_WXJSObject_filedID_type = nullptr;
diff --git a/weex_core/Source/android/wrap/wx_map.cpp b/weex_core/Source/android/wrap/wx_map.cpp
index 116d754..2470ab4 100644
--- a/weex_core/Source/android/wrap/wx_map.cpp
+++ b/weex_core/Source/android/wrap/wx_map.cpp
@@ -24,7 +24,7 @@
 #include "base/android/jni/android_jni.h"
 
 namespace WeexCore {
-const char kWXMapClassPath[] = "com/taobao/weex/utils/WXMap";
+const char kWXMapClassPath[] = "org/apache/weex/utils/WXMap";
 jclass g_WXMap_clazz = nullptr;
 
 static intptr_t g_WXMap_constructor = 0;
diff --git a/weex_core/Source/base/android/jniprebuild/jni_files b/weex_core/Source/base/android/jniprebuild/jni_files
index 1662c27..c8276c5 100644
--- a/weex_core/Source/base/android/jniprebuild/jni_files
+++ b/weex_core/Source/base/android/jniprebuild/jni_files
@@ -1 +1 @@
-com/taobao/weex/bridge/WXBridge.java
+org/apache/weex/bridge/WXBridge.java
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h
index dd92724..5a055e9 100644
--- a/weex_core/Source/base/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h
@@ -21,7 +21,7 @@
 // This file is autogenerated by
 //    weex-core2/weex_core/Source/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/layout/ContentBoxMeasurement
+//     org/apache/weex/layout/ContentBoxMeasurement
 
 #ifndef com_taobao_weex_layout_ContentBoxMeasurement_JNI
 #define com_taobao_weex_layout_ContentBoxMeasurement_JNI
@@ -33,7 +33,7 @@
 // Step 1: forward declarations.
 namespace {
 const char kContentBoxMeasurementClassPath[] =
-    "com/taobao/weex/layout/ContentBoxMeasurement";
+    "org/apache/weex/layout/ContentBoxMeasurement";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_ContentBoxMeasurement_clazz = NULL;
 #define ContentBoxMeasurement_clazz(env) g_ContentBoxMeasurement_clazz
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h
index 2a71a70..e15dac3 100644
--- a/weex_core/Source/base/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h
@@ -20,7 +20,7 @@
 // This file is autogenerated by
 //     incubator-weex/weex_core/Source/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils
+//     org/apache/weex/ui/component/list/template/jni/NativeRenderObjectUtils
 
 #ifndef com_taobao_weex_ui_component_list_template_jni_NativeRenderObjectUtils_JNI
 #define com_taobao_weex_ui_component_list_template_jni_NativeRenderObjectUtils_JNI
@@ -32,7 +32,7 @@
 // Step 1: forward declarations.
 namespace {
 const char kNativeRenderObjectUtilsClassPath[] =
-    "com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils";
+    "org/apache/weex/ui/component/list/template/jni/NativeRenderObjectUtils";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_NativeRenderObjectUtils_clazz = NULL;
 #define NativeRenderObjectUtils_clazz(env) g_NativeRenderObjectUtils_clazz
@@ -107,7 +107,7 @@
       "updateComponentSize",
 
 "("
-"Lcom/taobao/weex/ui/component/WXComponent;"
+"Lorg/apache/weex/ui/component/WXComponent;"
 "F"
 "F"
 "F"
@@ -189,7 +189,7 @@
     { "nativeRenderObjectUpdateComponent",
 "("
 "J"
-"Lcom/taobao/weex/ui/component/WXComponent;"
+"Lorg/apache/weex/ui/component/WXComponent;"
 ")"
 "V", reinterpret_cast<void*>(RenderObjectUpdateComponent) },
     { "nativeRenderObjectChildWaste",
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/RequestHandler_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/RequestHandler_jni.h
index e4ffd3c..d2eb6dd 100644
--- a/weex_core/Source/base/android/jniprebuild/jniheader/RequestHandler_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/RequestHandler_jni.h
@@ -20,7 +20,7 @@
 // This file is autogenerated by
 //     weex/weex_core/Source/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/bridge/RequestHandler
+//     org/apache/weex/bridge/RequestHandler
 
 #ifndef com_taobao_weex_bridge_RequestHandler_JNI
 #define com_taobao_weex_bridge_RequestHandler_JNI
@@ -31,7 +31,7 @@
 
 // Step 1: forward declarations.
 namespace {
-const char kRequestHandlerClassPath[] = "com/taobao/weex/bridge/RequestHandler";
+const char kRequestHandlerClassPath[] = "org/apache/weex/bridge/RequestHandler";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_RequestHandler_clazz = NULL;
 #define RequestHandler_clazz(env) g_RequestHandler_clazz
@@ -62,7 +62,7 @@
 
 "("
 ")"
-"Lcom/taobao/weex/bridge/RequestHandler;",
+"Lorg/apache/weex/bridge/RequestHandler;",
       &g_RequestHandler_create);
 
   jobject ret =
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/SystemMessageHandler_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/SystemMessageHandler_jni.h
index 3df56e9..bebf2e5 100644
--- a/weex_core/Source/base/android/jniprebuild/jniheader/SystemMessageHandler_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/SystemMessageHandler_jni.h
@@ -20,7 +20,7 @@
 // This file is autogenerated by
 //     incubator-weex/weex_core/Source/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/base/SystemMessageHandler
+//     org/apache/weex/base/SystemMessageHandler
 
 #ifndef com_taobao_weex_base_SystemMessageHandler_JNI
 #define com_taobao_weex_base_SystemMessageHandler_JNI
@@ -32,7 +32,7 @@
 // Step 1: forward declarations.
 namespace {
 const char kSystemMessageHandlerClassPath[] =
-    "com/taobao/weex/base/SystemMessageHandler";
+    "org/apache/weex/base/SystemMessageHandler";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_SystemMessageHandler_clazz = NULL;
 #define SystemMessageHandler_clazz(env) g_SystemMessageHandler_clazz
@@ -60,7 +60,7 @@
 "("
 "J"
 ")"
-"Lcom/taobao/weex/base/SystemMessageHandler;",
+"Lorg/apache/weex/base/SystemMessageHandler;",
       &g_SystemMessageHandler_create);
 
   jobject ret =
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h
index f7955cd..b1fef6f 100755
--- a/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h
@@ -20,7 +20,7 @@
 // This file is autogenerated by
 //     incubator-weex/weex_core/Source/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/bridge/WXBridge
+//     org/apache/weex/bridge/WXBridge
 
 #ifndef com_taobao_weex_bridge_WXBridge_JNI
 #define com_taobao_weex_bridge_WXBridge_JNI
@@ -32,7 +32,7 @@
 
 // Step 1: forward declarations.
 namespace {
-const char kWXBridgeClassPath[] = "com/taobao/weex/bridge/WXBridge";
+const char kWXBridgeClassPath[] = "org/apache/weex/bridge/WXBridge";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_WXBridge_clazz = NULL;
 #define WXBridge_clazz(env) g_WXBridge_clazz
@@ -1077,7 +1077,7 @@
           "Ljava/lang/String;"
           "J"
           ")"
-          "Lcom/taobao/weex/layout/ContentBoxMeasurement;",
+          "Lorg/apache/weex/layout/ContentBoxMeasurement;",
           &g_WXBridge_getMeasurementFunc);
 
   jobject ret =
@@ -1144,7 +1144,7 @@
     {"nativeInitFrameworkEnv",
      "("
      "Ljava/lang/String;"
-     "Lcom/taobao/weex/bridge/WXParams;"
+     "Lorg/apache/weex/bridge/WXParams;"
      "Ljava/lang/String;"
      "Z"
      ")"
@@ -1152,7 +1152,7 @@
     {"nativeInitFramework",
      "("
      "Ljava/lang/String;"
-     "Lcom/taobao/weex/bridge/WXParams;"
+     "Lorg/apache/weex/bridge/WXParams;"
      ")"
      "I", reinterpret_cast<void *>(InitFramework)},
     {"nativeRefreshInstance",
@@ -1160,7 +1160,7 @@
      "Ljava/lang/String;"
      "Ljava/lang/String;"
      "Ljava/lang/String;"
-     "[Lcom/taobao/weex/bridge/WXJSObject;"
+     "[Lorg/apache/weex/bridge/WXJSObject;"
      ")"
      "V", reinterpret_cast<void *>(RefreshInstance)},
     {"nativeExecJS",
@@ -1168,7 +1168,7 @@
      "Ljava/lang/String;"
      "Ljava/lang/String;"
      "Ljava/lang/String;"
-     "[Lcom/taobao/weex/bridge/WXJSObject;"
+     "[Lorg/apache/weex/bridge/WXJSObject;"
      ")"
      "I", reinterpret_cast<void *>(ExecJS)},
     {"nativeExecJSService",
@@ -1181,7 +1181,7 @@
      "Ljava/lang/String;"
      "Ljava/lang/String;"
      "Ljava/lang/String;"
-     "[Lcom/taobao/weex/bridge/WXJSObject;"
+     "[Lorg/apache/weex/bridge/WXJSObject;"
      "J"
      ")"
      "V", reinterpret_cast<void *>(ExecJSWithCallback)},
@@ -1190,7 +1190,7 @@
      "Ljava/lang/String;"
      "Ljava/lang/String;"
      "Ljava/lang/String;"
-     "[Lcom/taobao/weex/bridge/WXJSObject;"
+     "[Lorg/apache/weex/bridge/WXJSObject;"
      ")"
      "I", reinterpret_cast<void *>(CreateInstanceContext)},
     {"nativeDestoryInstance",
@@ -1198,7 +1198,7 @@
      "Ljava/lang/String;"
      "Ljava/lang/String;"
      "Ljava/lang/String;"
-     "[Lcom/taobao/weex/bridge/WXJSObject;"
+     "[Lorg/apache/weex/bridge/WXJSObject;"
      ")"
      "I", reinterpret_cast<void *>(DestoryInstance)},
     {"nativeExecJSOnInstance",
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/WXDebugJsBridge_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/WXDebugJsBridge_jni.h
index 458f435..78859ce 100644
--- a/weex_core/Source/base/android/jniprebuild/jniheader/WXDebugJsBridge_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/WXDebugJsBridge_jni.h
@@ -20,7 +20,7 @@
 // This file is autogenerated by
 //     weex_core_debug/Source/WeexCore/platform/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/bridge/WxDebugJsBridge
+//     org/apache/weex/bridge/WxDebugJsBridge
 
 #ifndef WEEX_PROJECT_WXDEBUGJSBRIDGE_JNI_H
 #define WEEX_PROJECT_WXDEBUGJSBRIDGE_JNI_H
@@ -29,7 +29,7 @@
 #include "base/android/jni/android_jni.h"
 
 namespace {
-    const char kWXDebugJsBridgeClassPath[] = "com/taobao/weex/bridge/WXDebugJsBridge";
+    const char kWXDebugJsBridgeClassPath[] = "org/apache/weex/bridge/WXDebugJsBridge";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
     jclass g_WXDebugJsBridge_clazz = NULL;
 #define WXDebugJsBridge_clazz(env) g_WXDebugJsBridge_clazz
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/WXJsFunctions_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/WXJsFunctions_jni.h
index 2a18241..62a6e5e 100644
--- a/weex_core/Source/base/android/jniprebuild/jniheader/WXJsFunctions_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/WXJsFunctions_jni.h
@@ -20,7 +20,7 @@
 // This file is autogenerated by
 //     weex_core_debug/Source/WeexCore/platform/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/bridge/JsFunctions
+//     org/apache/weex/bridge/JsFunctions
 
 #ifndef WEEX_PROJECT_WXJSFUNCTIONS_JNI_H
 #define WEEX_PROJECT_WXJSFUNCTIONS_JNI_H
@@ -29,7 +29,7 @@
 #include "base/android/jni/android_jni.h"
 
 namespace {
-    const char kWXJsFunctionClassPath[] = "com/taobao/weex/bridge/WXJsFunctions";
+    const char kWXJsFunctionClassPath[] = "org/apache/weex/bridge/WXJsFunctions";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
     jclass g_WXJsFunction_clazz = NULL;
 #define WXJsFunction_clazz(env) g_WXJsFunction_clazz
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/WXParams_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/WXParams_jni.h
index a215be4..7b68ba8 100644
--- a/weex_core/Source/base/android/jniprebuild/jniheader/WXParams_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/WXParams_jni.h
@@ -20,7 +20,7 @@
 // This file is autogenerated by
 //     incubator-weex/weex_core/Source/android/jniprebuild/jni_generator.py
 // For
-//     com/taobao/weex/bridge/WXParams
+//     org/apache/weex/bridge/WXParams
 
 #ifndef com_taobao_weex_bridge_WXParams_JNI
 #define com_taobao_weex_bridge_WXParams_JNI
@@ -32,7 +32,7 @@
 
 // Step 1: forward declarations.
 namespace {
-const char kWXParamsClassPath[] = "com/taobao/weex/bridge/WXParams";
+const char kWXParamsClassPath[] = "org/apache/weex/bridge/WXParams";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_WXParams_clazz = NULL;
 #define WXParams_clazz(env) g_WXParams_clazz
diff --git a/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp b/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
index 710ce35..31dcbf1 100644
--- a/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
+++ b/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
@@ -394,8 +394,11 @@
     args->value.string = genWeexString(
         reinterpret_cast<const uint16_t*>(utf16_key.c_str()), utf16_key.size());
     msg.push_back(args);
-
-    WeexCore::WeexCoreManager::Instance()->script_bridge()->script_side()->ExecJS(
+    ScriptBridge* bridge = WeexCore::WeexCoreManager::Instance()->script_bridge();
+    if (!bridge){
+      return false;
+    }
+    bridge->script_side()->ExecJS(
         instanceId, "", "callJS", msg);
     freeParams(msg);
     return true;
diff --git a/weex_core/Source/core/layout/layout.h b/weex_core/Source/core/layout/layout.h
index 6217972..e8d58f7 100644
--- a/weex_core/Source/core/layout/layout.h
+++ b/weex_core/Source/core/layout/layout.h
@@ -731,6 +731,10 @@
       
       markDirty();
     }
+      
+    inline void clearBFCs() {
+        BFCs.clear();
+    }
 
     inline void addChildAt(WXCoreLayoutNode* const child, Index index) {
       mChildList.insert(mChildList.begin() + index, child);
diff --git a/weex_core/Source/core/render/page/render_page.cpp b/weex_core/Source/core/render/page/render_page.cpp
index f13b271..7560848 100755
--- a/weex_core/Source/core/render/page/render_page.cpp
+++ b/weex_core/Source/core/render/page/render_page.cpp
@@ -221,6 +221,16 @@
     }
   }
 
+  if(index > new_parent->getChildCount()){
+    std::stringstream msg;
+    msg << "Out of array bounds when RenderPage::MoveRenderObject, specified index: "
+    << index << "array size " << new_parent->getChildCount();
+
+    WeexCore::WeexCoreManager::Instance()->getPlatformBridge()->platform_side()
+    ->ReportException(page_id().c_str(), "RenderPage::MoveRenderObject", msg.str().c_str());
+    return false;
+  }
+
   set_is_dirty(true);
   child->getParent()->removeChild(child);
   new_parent->addChildAt(child, index);
diff --git a/weex_core/Source/js_runtime/CMakeLists.txt b/weex_core/Source/js_runtime/CMakeLists.txt
index 42bd160..139209a 100644
--- a/weex_core/Source/js_runtime/CMakeLists.txt
+++ b/weex_core/Source/js_runtime/CMakeLists.txt
@@ -86,8 +86,7 @@
 
 include_directories(${WEEX_CORE_SOURCE_DIR})
 include_directories(${WEEX_CORE_SOURCE_DIR}/include)
-include_directories(${WEEX_CORE_SOURCE_DIR}/include/JavaScriptCore)
-include_directories(${WEEX_CORE_SOURCE_DIR}/include/JavaScriptCore/ForwardingHeaders)
+include_directories(${WEEX_CORE_SOURCE_DIR}/include/JSCHeaderNew)
 
 
 
@@ -212,10 +211,6 @@
 weexbase
 weexipc
 wson
-#c++_shared
-JavaScriptCore
-WTF
-#jsc
 log
 z
 -lc
@@ -223,6 +218,20 @@
 -pthread
 )
 
+if (DEFINED BUILD_RUNTIME_API)
+    set(${WEEXJSSERVER_NAME}_LIBRARIES
+        ${${WEEXJSSERVER_NAME}_LIBRARIES}
+        c++_shared
+        jsc
+    )
+else()
+    set(${WEEXJSSERVER_NAME}_LIBRARIES
+        ${${WEEXJSSERVER_NAME}_LIBRARIES}
+        JavaScriptCore
+        WTF
+    )
+endif()
+
 add_library(${WEEXJSSERVER_NAME} SHARED
             ${${WEEXJSSERVER_NAME}_SOURCES} )
 
diff --git a/weex_core/Source/js_runtime/weex/utils/weex_jsc_utils.h b/weex_core/Source/js_runtime/weex/utils/weex_jsc_utils.h
index 30a87d8..a4a2701 100644
--- a/weex_core/Source/js_runtime/weex/utils/weex_jsc_utils.h
+++ b/weex_core/Source/js_runtime/weex/utils/weex_jsc_utils.h
@@ -209,6 +209,7 @@
 //    }
 
     static bool initICUEnv(bool multiProcess) {
+#ifdef INIT_JSC_PRIVATE_API
         static bool isInit = false;
         if (isInit)
             return true;
@@ -245,6 +246,10 @@
             return true;//mapIcuData(std::string(path));
         }
         return false;
+#else
+        LOGE("skip initICUEnv");
+        return true;
+#endif
     }
 
 }
diff --git a/weex_core/Source/libs/arm64-v8a/libJavaScriptCore.so b/weex_core/Source/libs/arm64-v8a/libJavaScriptCore.so
deleted file mode 100755
index 56307f0..0000000
--- a/weex_core/Source/libs/arm64-v8a/libJavaScriptCore.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/libs/arm64-v8a/libWTF.so b/weex_core/Source/libs/arm64-v8a/libWTF.so
deleted file mode 100755
index ce8d0bc..0000000
--- a/weex_core/Source/libs/arm64-v8a/libWTF.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/libs/armeabi-v7a/libJavaScriptCore.so b/weex_core/Source/libs/armeabi-v7a/libJavaScriptCore.so
deleted file mode 100755
index 2d59099..0000000
--- a/weex_core/Source/libs/armeabi-v7a/libJavaScriptCore.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/libs/armeabi-v7a/libWTF.so b/weex_core/Source/libs/armeabi-v7a/libWTF.so
deleted file mode 100755
index 790bef2..0000000
--- a/weex_core/Source/libs/armeabi-v7a/libWTF.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/libs/armeabi/libJavaScriptCore.so b/weex_core/Source/libs/armeabi/libJavaScriptCore.so
deleted file mode 100755
index 2d59099..0000000
--- a/weex_core/Source/libs/armeabi/libJavaScriptCore.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/libs/armeabi/libWTF.so b/weex_core/Source/libs/armeabi/libWTF.so
deleted file mode 100755
index 790bef2..0000000
--- a/weex_core/Source/libs/armeabi/libWTF.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/libs/x86/libJavaScriptCore.so b/weex_core/Source/libs/x86/libJavaScriptCore.so
deleted file mode 100755
index b7abc27..0000000
--- a/weex_core/Source/libs/x86/libJavaScriptCore.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/libs/x86/libWTF.so b/weex_core/Source/libs/x86/libWTF.so
deleted file mode 100755
index 0f4c2df..0000000
--- a/weex_core/Source/libs/x86/libWTF.so
+++ /dev/null
Binary files differ
diff --git a/weex_core/Source/third_party/json11/CMakeLists.txt b/weex_core/Source/third_party/json11/CMakeLists.txt
index 148c31f..ed876dd 100644
--- a/weex_core/Source/third_party/json11/CMakeLists.txt
+++ b/weex_core/Source/third_party/json11/CMakeLists.txt
@@ -1,3 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
 cmake_minimum_required(VERSION 3.4.1)
 
 set(JSON11_LIBRARY_NAME json11)